Merge branch 'pci/hotplug' into next

* pci/hotplug:
  PCI: pciehp: Do not clear Presence Detect Changed during initialization
  PCI: pciehp: Fix race condition handling surprise link down
  PCI: Distribute available resources to hotplug-capable bridges
  PCI: Distribute available buses to hotplug-capable bridges
  PCI: Do not allocate more buses than available in parent
  PCI: Open-code the two pass loop when scanning bridges
  PCI: Move pci_hp_add_bridge() to drivers/pci/probe.c
  PCI: Add for_each_pci_bridge() helper
  PCI: shpchp: Convert timers to use timer_setup()
  PCI: cpqphp: Convert timers to use timer_setup()
  PCI: pciehp: Convert timers to use timer_setup()
  PCI: ibmphp: Use common error handling code in unconfigure_boot_device()
This commit is contained in:
Bjorn Helgaas 2017-11-14 12:11:22 -06:00
commit 8d666e53e0
17 changed files with 419 additions and 116 deletions

View File

@ -16,9 +16,6 @@ obj-$(CONFIG_PCIEPORTBUS) += pcie/
# Build the PCI Hotplug drivers if we were asked to
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
ifdef CONFIG_HOTPLUG_PCI
obj-y += hotplug-pci.o
endif
# Build the PCI MSI interrupt support
obj-$(CONFIG_PCI_MSI) += msi.o

View File

@ -1,29 +0,0 @@
/* Core PCI functionality used only by PCI hotplug */
#include <linux/pci.h>
#include <linux/export.h>
#include "pci.h"
int pci_hp_add_bridge(struct pci_dev *dev)
{
struct pci_bus *parent = dev->bus;
int pass, busnr, start = parent->busn_res.start;
int end = parent->busn_res.end;
for (busnr = start; busnr <= end; busnr++) {
if (!pci_find_bus(pci_domain_nr(parent), busnr))
break;
}
if (busnr-- > end) {
printk(KERN_ERR "No bus number available for hot-added bridge %s\n",
pci_name(dev));
return -1;
}
for (pass = 0; pass < 2; pass++)
busnr = pci_scan_bridge(parent, dev, busnr, pass);
if (!dev->subordinate)
return -1;
return 0;
}
EXPORT_SYMBOL_GPL(pci_hp_add_bridge);

View File

@ -462,18 +462,15 @@ static void enable_slot(struct acpiphp_slot *slot)
acpiphp_rescan_slot(slot);
max = acpiphp_max_busnr(bus);
for (pass = 0; pass < 2; pass++) {
list_for_each_entry(dev, &bus->devices, bus_list) {
for_each_pci_bridge(dev, bus) {
if (PCI_SLOT(dev->devfn) != slot->device)
continue;
if (pci_is_bridge(dev)) {
max = pci_scan_bridge(bus, dev, max, pass);
if (pass && dev->subordinate) {
check_hotplug_bridge(slot, dev);
pcibios_resource_survey_bus(dev->subordinate);
__pci_bus_size_bridges(dev->subordinate,
&add_list);
}
max = pci_scan_bridge(bus, dev, max, pass);
if (pass && dev->subordinate) {
check_hotplug_bridge(slot, dev);
pcibios_resource_survey_bus(dev->subordinate);
__pci_bus_size_bridges(dev->subordinate, &add_list);
}
}
}

View File

@ -286,14 +286,11 @@ int cpci_configure_slot(struct slot *slot)
}
parent = slot->dev->bus;
list_for_each_entry(dev, &parent->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
continue;
if (pci_is_bridge(dev))
for_each_pci_bridge(dev, parent) {
if (PCI_SLOT(dev->devfn) == PCI_SLOT(slot->devfn))
pci_hp_add_bridge(dev);
}
pci_assign_unassigned_bridge_resources(parent->self);
pci_bus_add_devices(parent);

View File

@ -410,7 +410,7 @@ void cpqhp_create_debugfs_files(struct controller *ctrl);
void cpqhp_remove_debugfs_files(struct controller *ctrl);
/* controller functions */
void cpqhp_pushbutton_thread(unsigned long event_pointer);
void cpqhp_pushbutton_thread(struct timer_list *t);
irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data);
int cpqhp_find_available_resources(struct controller *ctrl,
void __iomem *rom_start);

View File

@ -661,9 +661,8 @@ static int ctrl_slot_setup(struct controller *ctrl,
slot->p_sm_slot = slot_entry;
init_timer(&slot->task_event);
timer_setup(&slot->task_event, cpqhp_pushbutton_thread, 0);
slot->task_event.expires = jiffies + 5 * HZ;
slot->task_event.function = cpqhp_pushbutton_thread;
/*FIXME: these capabilities aren't used but if they are
* they need to be correctly implemented

View File

@ -47,7 +47,7 @@ static void interrupt_event_handler(struct controller *ctrl);
static struct task_struct *cpqhp_event_thread;
static unsigned long pushbutton_pending; /* = 0 */
static struct timer_list *pushbutton_pending; /* = NULL */
/* delay is in jiffies to wait for */
static void long_delay(int delay)
@ -1732,9 +1732,10 @@ static u32 remove_board(struct pci_func *func, u32 replace_flag, struct controll
return 0;
}
static void pushbutton_helper_thread(unsigned long data)
static void pushbutton_helper_thread(struct timer_list *t)
{
pushbutton_pending = data;
pushbutton_pending = t;
wake_up_process(cpqhp_event_thread);
}
@ -1883,13 +1884,13 @@ static void interrupt_event_handler(struct controller *ctrl)
wait_for_ctrl_irq(ctrl);
mutex_unlock(&ctrl->crit_sect);
init_timer(&p_slot->task_event);
timer_setup(&p_slot->task_event,
pushbutton_helper_thread,
0);
p_slot->hp_slot = hp_slot;
p_slot->ctrl = ctrl;
/* p_slot->physical_slot = physical_slot; */
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
p_slot->task_event.function = pushbutton_helper_thread;
p_slot->task_event.data = (u32) p_slot;
dbg("add_timer p_slot = %p\n", p_slot);
add_timer(&p_slot->task_event);
@ -1920,15 +1921,15 @@ static void interrupt_event_handler(struct controller *ctrl)
* Scheduled procedure to handle blocking stuff for the pushbuttons.
* Handles all pending events and exits.
*/
void cpqhp_pushbutton_thread(unsigned long slot)
void cpqhp_pushbutton_thread(struct timer_list *t)
{
u8 hp_slot;
u8 device;
struct pci_func *func;
struct slot *p_slot = (struct slot *) slot;
struct slot *p_slot = from_timer(p_slot, t, task_event);
struct controller *ctrl = (struct controller *) p_slot->ctrl;
pushbutton_pending = 0;
pushbutton_pending = NULL;
hp_slot = p_slot->hp_slot;
device = p_slot->device;

View File

@ -1267,20 +1267,19 @@ static int unconfigure_boot_device(u8 busno, u8 device, u8 function)
size = size & 0xFFFFFFFC;
size = ~size + 1;
end_address = start_address + size - 1;
if (ibmphp_find_resource(bus, start_address, &io, IO) < 0) {
err("cannot find corresponding IO resource to remove\n");
return -EIO;
}
if (ibmphp_find_resource(bus, start_address, &io, IO))
goto report_search_failure;
debug("io->start = %x\n", io->start);
temp_end = io->end;
start_address = io->end + 1;
ibmphp_remove_resource(io);
/* This is needed b/c of the old I/O restrictions in the BIOS */
while (temp_end < end_address) {
if (ibmphp_find_resource(bus, start_address, &io, IO) < 0) {
err("cannot find corresponding IO resource to remove\n");
return -EIO;
}
if (ibmphp_find_resource(bus, start_address,
&io, IO))
goto report_search_failure;
debug("io->start = %x\n", io->start);
temp_end = io->end;
start_address = io->end + 1;
@ -1327,6 +1326,10 @@ static int unconfigure_boot_device(u8 busno, u8 device, u8 function)
} /* end of for */
return 0;
report_search_failure:
err("cannot find corresponding IO resource to remove\n");
return -EIO;
}
static int unconfigure_boot_bridge(u8 busno, u8 device, u8 function)

View File

@ -113,10 +113,11 @@ static int board_added(struct slot *p_slot)
retval = pciehp_configure_device(p_slot);
if (retval) {
ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
pci_domain_nr(parent), parent->number);
if (retval != -EEXIST)
if (retval != -EEXIST) {
ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
pci_domain_nr(parent), parent->number);
goto err_exit;
}
}
pciehp_green_led_on(p_slot);

View File

@ -50,14 +50,13 @@ static irqreturn_t pcie_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct controller *ctrl, int sec);
/* This is the interrupt polling timeout function. */
static void int_poll_timeout(unsigned long data)
static void int_poll_timeout(struct timer_list *t)
{
struct controller *ctrl = (struct controller *)data;
struct controller *ctrl = from_timer(ctrl, t, poll_timer);
/* Poll for interrupt events. regs == NULL => polling */
pcie_isr(0, ctrl);
init_timer(&ctrl->poll_timer);
if (!pciehp_poll_time)
pciehp_poll_time = 2; /* default polling interval is 2 sec */
@ -71,8 +70,6 @@ static void start_int_poll_timer(struct controller *ctrl, int sec)
if ((sec <= 0) || (sec > 60))
sec = 2;
ctrl->poll_timer.function = &int_poll_timeout;
ctrl->poll_timer.data = (unsigned long)ctrl;
ctrl->poll_timer.expires = jiffies + sec * HZ;
add_timer(&ctrl->poll_timer);
}
@ -83,7 +80,7 @@ static inline int pciehp_request_irq(struct controller *ctrl)
/* Install interrupt polling timer. Start with 10 sec delay */
if (pciehp_poll_mode) {
init_timer(&ctrl->poll_timer);
timer_setup(&ctrl->poll_timer, int_poll_timeout, 0);
start_int_poll_timer(ctrl, 10);
return 0;
}
@ -764,8 +761,7 @@ int pciehp_reset_slot(struct slot *slot, int probe)
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask);
if (pciehp_poll_mode)
int_poll_timeout(ctrl->poll_timer.data);
int_poll_timeout(&ctrl->poll_timer);
return 0;
}
@ -795,7 +791,7 @@ static int pcie_init_slot(struct controller *ctrl)
if (!slot)
return -ENOMEM;
slot->wq = alloc_workqueue("pciehp-%u", 0, 0, PSN(ctrl));
slot->wq = alloc_ordered_workqueue("pciehp-%u", 0, PSN(ctrl));
if (!slot->wq)
goto abort;
@ -862,11 +858,16 @@ struct controller *pcie_init(struct pcie_device *dev)
if (link_cap & PCI_EXP_LNKCAP_DLLLARC)
ctrl->link_active_reporting = 1;
/* Clear all remaining event bits in Slot Status register */
/*
* Clear all remaining event bits in Slot Status register except
* Presence Detect Changed. We want to make sure possible
* hotplug event is triggered when the interrupt is unmasked so
* that we don't lose that event.
*/
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC |
PCI_EXP_SLTSTA_DLLSC);
ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c LLActRep%c\n",
(slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,

View File

@ -46,7 +46,11 @@ int pciehp_configure_device(struct slot *p_slot)
dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
if (dev) {
ctrl_err(ctrl, "Device %s already exists at %04x:%02x:00, cannot hot-add\n",
/*
* The device is already there. Either configured by the
* boot firmware or a previous hotplug event.
*/
ctrl_dbg(ctrl, "Device %s already exists at %04x:%02x:00, skipping hot-add\n",
pci_name(dev), pci_domain_nr(parent), parent->number);
pci_dev_put(dev);
ret = -EEXIST;
@ -60,9 +64,8 @@ int pciehp_configure_device(struct slot *p_slot)
goto out;
}
list_for_each_entry(dev, &parent->devices, bus_list)
if (pci_is_bridge(dev))
pci_hp_add_bridge(dev);
for_each_pci_bridge(dev, parent)
pci_hp_add_bridge(dev);
pci_assign_unassigned_bridge_resources(bridge);
pcie_bus_configure_settings(parent);

View File

@ -229,14 +229,13 @@ static inline int shpc_indirect_read(struct controller *ctrl, int index,
/*
* This is the interrupt polling timeout function.
*/
static void int_poll_timeout(unsigned long data)
static void int_poll_timeout(struct timer_list *t)
{
struct controller *ctrl = (struct controller *)data;
struct controller *ctrl = from_timer(ctrl, t, poll_timer);
/* Poll for interrupt events. regs == NULL => polling */
shpc_isr(0, ctrl);
init_timer(&ctrl->poll_timer);
if (!shpchp_poll_time)
shpchp_poll_time = 2; /* default polling interval is 2 sec */
@ -252,8 +251,6 @@ static void start_int_poll_timer(struct controller *ctrl, int sec)
if ((sec <= 0) || (sec > 60))
sec = 2;
ctrl->poll_timer.function = &int_poll_timeout;
ctrl->poll_timer.data = (unsigned long)ctrl;
ctrl->poll_timer.expires = jiffies + sec * HZ;
add_timer(&ctrl->poll_timer);
}
@ -1054,7 +1051,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
if (shpchp_poll_mode) {
/* Install interrupt polling timer. Start with 10 sec delay */
init_timer(&ctrl->poll_timer);
timer_setup(&ctrl->poll_timer, int_poll_timeout, 0);
start_int_poll_timer(ctrl, 10);
} else {
/* Installs the interrupt handler */

View File

@ -61,10 +61,8 @@ int shpchp_configure_device(struct slot *p_slot)
goto out;
}
list_for_each_entry(dev, &parent->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != p_slot->device)
continue;
if (pci_is_bridge(dev))
for_each_pci_bridge(dev, parent) {
if (PCI_SLOT(dev->devfn) == p_slot->device)
pci_hp_add_bridge(dev);
}

View File

@ -959,7 +959,21 @@ static void pci_enable_crs(struct pci_dev *pdev)
PCI_EXP_RTCTL_CRSSVE);
}
static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
unsigned int available_buses);
/*
* pci_scan_bridge_extend() - Scan buses behind a bridge
* @bus: Parent bus the bridge is on
* @dev: Bridge itself
* @max: Starting subordinate number of buses behind this bridge
* @available_buses: Total number of buses available for this bridge and
* the devices below. After the minimal bus space has
* been allocated the remaining buses will be
* distributed equally between hotplug-capable bridges.
* @pass: Either %0 (scan already configured bridges) or %1 (scan bridges
* that need to be reconfigured.
*
* 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.
@ -969,7 +983,9 @@ static void pci_enable_crs(struct pci_dev *pdev)
* them, we proceed to assigning numbers to the remaining buses in
* order to avoid overlaps between old and new bus numbers.
*/
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
int max, unsigned int available_buses,
int pass)
{
struct pci_bus *child;
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
@ -1076,9 +1092,13 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
child = pci_add_new_bus(bus, dev, max+1);
if (!child)
goto out;
pci_bus_insert_busn_res(child, max+1, 0xff);
pci_bus_insert_busn_res(child, max+1,
bus->busn_res.end);
}
max++;
if (available_buses)
available_buses--;
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->busn_res.start) << 8)
@ -1100,7 +1120,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
if (!is_cardbus) {
child->bridge_ctl = bctl;
max = pci_scan_child_bus(child);
max = pci_scan_child_bus_extend(child, available_buses);
} else {
/*
* For CardBus bridges, we leave 4 bus numbers
@ -1168,6 +1188,28 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
return max;
}
/*
* pci_scan_bridge() - Scan buses behind a bridge
* @bus: Parent bus the bridge is on
* @dev: Bridge itself
* @max: Starting subordinate number of buses behind this bridge
* @pass: Either %0 (scan already configured bridges) or %1 (scan bridges
* that need to be reconfigured.
*
* 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.
*/
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
{
return pci_scan_bridge_extend(bus, dev, max, 0, pass);
}
EXPORT_SYMBOL(pci_scan_bridge);
/*
@ -2396,9 +2438,24 @@ void __weak pcibios_fixup_bus(struct pci_bus *bus)
/* nothing to do, expected to be removed in the future */
}
unsigned int pci_scan_child_bus(struct pci_bus *bus)
/**
* pci_scan_child_bus_extend() - Scan devices below a bus
* @bus: Bus to scan for devices
* @available_buses: Total number of buses available (%0 does not try to
* extend beyond the minimal)
*
* Scans devices below @bus including subordinate buses. Returns new
* subordinate number including all the found devices. Passing
* @available_buses causes the remaining bus space to be distributed
* equally between hotplug-capable bridges to allow future extension of the
* hierarchy.
*/
static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
unsigned int available_buses)
{
unsigned int devfn, pass, max = bus->busn_res.start;
unsigned int used_buses, normal_bridges = 0, hotplug_bridges = 0;
unsigned int start = bus->busn_res.start;
unsigned int devfn, cmax, max = start;
struct pci_dev *dev;
dev_dbg(&bus->dev, "scanning bus\n");
@ -2408,7 +2465,8 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
pci_scan_slot(bus, devfn);
/* Reserve buses for SR-IOV capability. */
max += pci_iov_bus_range(bus);
used_buses = pci_iov_bus_range(bus);
max += used_buses;
/*
* After performing arch-dependent fixup of the bus, look behind
@ -2420,19 +2478,73 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
bus->is_added = 1;
}
for (pass = 0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list) {
if (pci_is_bridge(dev))
max = pci_scan_bridge(bus, dev, max, pass);
/*
* Calculate how many hotplug bridges and normal bridges there
* are on this bus. We will distribute the additional available
* buses between hotplug bridges.
*/
for_each_pci_bridge(dev, bus) {
if (dev->is_hotplug_bridge)
hotplug_bridges++;
else
normal_bridges++;
}
/*
* Scan bridges that are already configured. We don't touch them
* unless they are misconfigured (which will be done in the second
* scan below).
*/
for_each_pci_bridge(dev, bus) {
cmax = max;
max = pci_scan_bridge_extend(bus, dev, max, 0, 0);
used_buses += cmax - max;
}
/* Scan bridges that need to be reconfigured */
for_each_pci_bridge(dev, bus) {
unsigned int buses = 0;
if (!hotplug_bridges && normal_bridges == 1) {
/*
* There is only one bridge on the bus (upstream
* port) so it gets all available buses which it
* can then distribute to the possible hotplug
* bridges below.
*/
buses = available_buses;
} else if (dev->is_hotplug_bridge) {
/*
* Distribute the extra buses between hotplug
* bridges if any.
*/
buses = available_buses / hotplug_bridges;
buses = min(buses, available_buses - used_buses);
}
cmax = max;
max = pci_scan_bridge_extend(bus, dev, cmax, buses, 1);
used_buses += max - cmax;
}
/*
* Make sure a hotplug bridge has at least the minimum requested
* number of buses.
* number of buses but allow it to grow up to the maximum available
* bus number of there is room.
*/
if (bus->self && bus->self->is_hotplug_bridge && pci_hotplug_bus_size) {
if (max - bus->busn_res.start < pci_hotplug_bus_size - 1)
max = bus->busn_res.start + pci_hotplug_bus_size - 1;
if (bus->self && bus->self->is_hotplug_bridge) {
used_buses = max_t(unsigned int, available_buses,
pci_hotplug_bus_size - 1);
if (max - start < used_buses) {
max = start + used_buses;
/* Do not allocate more buses than we have room left */
if (max > bus->busn_res.end)
max = bus->busn_res.end;
dev_dbg(&bus->dev, "%pR extended by %#02x\n",
&bus->busn_res, max - start);
}
}
/*
@ -2445,6 +2557,18 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max);
return max;
}
/**
* pci_scan_child_bus() - Scan devices below a bus
* @bus: Bus to scan for devices
*
* Scans devices below @bus including subordinate buses. Returns new
* subordinate number including all the found devices.
*/
unsigned int pci_scan_child_bus(struct pci_bus *bus)
{
return pci_scan_child_bus_extend(bus, 0);
}
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
/**
@ -2737,3 +2861,38 @@ void __init pci_sort_breadthfirst(void)
{
bus_sort_breadthfirst(&pci_bus_type, &pci_sort_bf_cmp);
}
int pci_hp_add_bridge(struct pci_dev *dev)
{
struct pci_bus *parent = dev->bus;
int busnr, start = parent->busn_res.start;
unsigned int available_buses = 0;
int end = parent->busn_res.end;
for (busnr = start; busnr <= end; busnr++) {
if (!pci_find_bus(pci_domain_nr(parent), busnr))
break;
}
if (busnr-- > end) {
dev_err(&dev->dev, "No bus number available for hot-added bridge\n");
return -1;
}
/* Scan bridges that are already configured */
busnr = pci_scan_bridge(parent, dev, busnr, 0);
/*
* Distribute the available bus numbers between hotplug-capable
* bridges to make extending the chain later possible.
*/
available_buses = end - busnr;
/* Scan bridges that need to be reconfigured */
pci_scan_bridge_extend(parent, dev, busnr, available_buses, 1);
if (!dev->subordinate)
return -1;
return 0;
}
EXPORT_SYMBOL_GPL(pci_hp_add_bridge);

View File

@ -1853,6 +1853,175 @@ void __init pci_assign_unassigned_resources(void)
}
}
static void extend_bridge_window(struct pci_dev *bridge, struct resource *res,
struct list_head *add_list, resource_size_t available)
{
struct pci_dev_resource *dev_res;
if (res->parent)
return;
if (resource_size(res) >= available)
return;
dev_res = res_to_dev_res(add_list, res);
if (!dev_res)
return;
/* Is there room to extend the window? */
if (available - resource_size(res) <= dev_res->add_size)
return;
dev_res->add_size = available - resource_size(res);
dev_dbg(&bridge->dev, "bridge window %pR extended by %pa\n", res,
&dev_res->add_size);
}
static void pci_bus_distribute_available_resources(struct pci_bus *bus,
struct list_head *add_list, resource_size_t available_io,
resource_size_t available_mmio, resource_size_t available_mmio_pref)
{
resource_size_t remaining_io, remaining_mmio, remaining_mmio_pref;
unsigned int normal_bridges = 0, hotplug_bridges = 0;
struct resource *io_res, *mmio_res, *mmio_pref_res;
struct pci_dev *dev, *bridge = bus->self;
io_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
mmio_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
mmio_pref_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
/*
* Update additional resource list (add_list) to fill all the
* extra resource space available for this port except the space
* calculated in __pci_bus_size_bridges() which covers all the
* devices currently connected to the port and below.
*/
extend_bridge_window(bridge, io_res, add_list, available_io);
extend_bridge_window(bridge, mmio_res, add_list, available_mmio);
extend_bridge_window(bridge, mmio_pref_res, add_list,
available_mmio_pref);
/*
* Calculate the total amount of extra resource space we can
* pass to bridges below this one. This is basically the
* extra space reduced by the minimal required space for the
* non-hotplug bridges.
*/
remaining_io = available_io;
remaining_mmio = available_mmio;
remaining_mmio_pref = available_mmio_pref;
/*
* Calculate how many hotplug bridges and normal bridges there
* are on this bus. We will distribute the additional available
* resources between hotplug bridges.
*/
for_each_pci_bridge(dev, bus) {
if (dev->is_hotplug_bridge)
hotplug_bridges++;
else
normal_bridges++;
}
for_each_pci_bridge(dev, bus) {
const struct resource *res;
if (dev->is_hotplug_bridge)
continue;
/*
* Reduce the available resource space by what the
* bridge and devices below it occupy.
*/
res = &dev->resource[PCI_BRIDGE_RESOURCES + 0];
if (!res->parent && available_io > resource_size(res))
remaining_io -= resource_size(res);
res = &dev->resource[PCI_BRIDGE_RESOURCES + 1];
if (!res->parent && available_mmio > resource_size(res))
remaining_mmio -= resource_size(res);
res = &dev->resource[PCI_BRIDGE_RESOURCES + 2];
if (!res->parent && available_mmio_pref > resource_size(res))
remaining_mmio_pref -= resource_size(res);
}
/*
* Go over devices on this bus and distribute the remaining
* resource space between hotplug bridges.
*/
for_each_pci_bridge(dev, bus) {
struct pci_bus *b;
b = dev->subordinate;
if (!b)
continue;
if (!hotplug_bridges && normal_bridges == 1) {
/*
* There is only one bridge on the bus (upstream
* port) so it gets all available resources
* which it can then distribute to the possible
* hotplug bridges below.
*/
pci_bus_distribute_available_resources(b, add_list,
available_io, available_mmio,
available_mmio_pref);
} else if (dev->is_hotplug_bridge) {
resource_size_t align, io, mmio, mmio_pref;
/*
* Distribute available extra resources equally
* between hotplug-capable downstream ports
* taking alignment into account.
*
* Here hotplug_bridges is always != 0.
*/
align = pci_resource_alignment(bridge, io_res);
io = div64_ul(available_io, hotplug_bridges);
io = min(ALIGN(io, align), remaining_io);
remaining_io -= io;
align = pci_resource_alignment(bridge, mmio_res);
mmio = div64_ul(available_mmio, hotplug_bridges);
mmio = min(ALIGN(mmio, align), remaining_mmio);
remaining_mmio -= mmio;
align = pci_resource_alignment(bridge, mmio_pref_res);
mmio_pref = div64_ul(available_mmio_pref,
hotplug_bridges);
mmio_pref = min(ALIGN(mmio_pref, align),
remaining_mmio_pref);
remaining_mmio_pref -= mmio_pref;
pci_bus_distribute_available_resources(b, add_list, io,
mmio, mmio_pref);
}
}
}
static void
pci_bridge_distribute_available_resources(struct pci_dev *bridge,
struct list_head *add_list)
{
resource_size_t available_io, available_mmio, available_mmio_pref;
const struct resource *res;
if (!bridge->is_hotplug_bridge)
return;
/* Take the initial extra resources from the hotplug port */
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
available_io = resource_size(res);
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
available_mmio = resource_size(res);
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
available_mmio_pref = resource_size(res);
pci_bus_distribute_available_resources(bridge->subordinate,
add_list, available_io, available_mmio, available_mmio_pref);
}
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
{
struct pci_bus *parent = bridge->subordinate;
@ -1867,6 +2036,14 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
again:
__pci_bus_size_bridges(parent, &add_list);
/*
* Distribute remaining resources (if any) equally between
* hotplug bridges below. This makes it possible to extend the
* hierarchy later without running out of resources.
*/
pci_bridge_distribute_available_resources(bridge, &add_list);
__pci_bridge_assign_resources(bridge, &add_list, &fail_head);
BUG_ON(!list_empty(&add_list));
tried_times++;
@ -1921,10 +2098,9 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
want additional resources */
down_read(&pci_bus_sem);
list_for_each_entry(dev, &bus->devices, bus_list)
if (pci_is_bridge(dev) && pci_has_subordinate(dev))
__pci_bus_size_bridges(dev->subordinate,
&add_list);
for_each_pci_bridge(dev, bus)
if (pci_has_subordinate(dev))
__pci_bus_size_bridges(dev->subordinate, &add_list);
up_read(&pci_bus_sem);
__pci_bus_assign_resources(bus, &add_list, NULL);
BUG_ON(!list_empty(&add_list));

View File

@ -77,9 +77,8 @@ int __ref cb_alloc(struct pcmcia_socket *s)
max = bus->busn_res.start;
for (pass = 0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list)
if (pci_is_bridge(dev))
max = pci_scan_bridge(bus, dev, max, pass);
for_each_pci_bridge(dev, bus)
max = pci_scan_bridge(bus, dev, max, pass);
/*
* Size all resources below the CardBus controller.

View File

@ -596,6 +596,10 @@ static inline bool pci_is_bridge(struct pci_dev *dev)
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
}
#define for_each_pci_bridge(dev, bus) \
list_for_each_entry(dev, &bus->devices, bus_list) \
if (!pci_is_bridge(dev)) {} else
static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev)
{
dev = pci_physfn(dev);