Merge branch 'pci/yijing-ari' into next

* pci/yijing-ari:
  PCI: shpchp: Iterate over all devices in slot, not functions 0-7
  PCI: sgihp: Iterate over all devices in slot, not functions 0-7
  PCI: cpcihp: Iterate over all devices in slot, not functions 0-7
  PCI: pciehp: Iterate over all devices in slot, not functions 0-7
  PCI: Consolidate "next-function" functions
  PCI: Rename pci_enable_ari() to pci_configure_ari()
  PCI: Enable ARI if dev and upstream bridge support it; disable otherwise
This commit is contained in:
Bjorn Helgaas 2013-01-26 17:27:36 -07:00
commit 14b5cb37cc
7 changed files with 109 additions and 136 deletions

View File

@ -252,8 +252,8 @@ int cpci_led_off(struct slot* slot)
int __ref cpci_configure_slot(struct slot *slot)
{
struct pci_dev *dev;
struct pci_bus *parent;
int fn;
dbg("%s - enter", __func__);
@ -282,18 +282,13 @@ int __ref cpci_configure_slot(struct slot *slot)
}
parent = slot->dev->bus;
for (fn = 0; fn < 8; fn++) {
struct pci_dev *dev;
dev = pci_get_slot(parent,
PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
if (!dev)
list_for_each_entry(dev, &parent->devices, bus_list)
if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
continue;
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
pci_hp_add_bridge(dev);
pci_dev_put(dev);
}
pci_assign_unassigned_bridge_resources(parent->self);
@ -305,8 +300,7 @@ int __ref cpci_configure_slot(struct slot *slot)
int cpci_unconfigure_slot(struct slot* slot)
{
int i;
struct pci_dev *dev;
struct pci_dev *dev, *temp;
dbg("%s - enter", __func__);
if (!slot->dev) {
@ -314,13 +308,12 @@ int cpci_unconfigure_slot(struct slot* slot)
return -ENODEV;
}
for (i = 0; i < 8; i++) {
dev = pci_get_slot(slot->bus,
PCI_DEVFN(PCI_SLOT(slot->devfn), i));
if (dev) {
pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
continue;
pci_dev_get(dev);
pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
pci_dev_put(slot->dev);
slot->dev = NULL;

View File

@ -39,7 +39,7 @@ int pciehp_configure_device(struct slot *p_slot)
struct pci_dev *dev;
struct pci_dev *bridge = p_slot->ctrl->pcie->port;
struct pci_bus *parent = bridge->subordinate;
int num, fn;
int num;
struct controller *ctrl = p_slot->ctrl;
dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
@ -57,28 +57,18 @@ int pciehp_configure_device(struct slot *p_slot)
return -ENODEV;
}
for (fn = 0; fn < 8; fn++) {
dev = pci_get_slot(parent, PCI_DEVFN(0, fn));
if (!dev)
continue;
list_for_each_entry(dev, &parent->devices, bus_list)
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
pci_hp_add_bridge(dev);
pci_dev_put(dev);
}
pci_assign_unassigned_bridge_resources(bridge);
for (fn = 0; fn < 8; fn++) {
dev = pci_get_slot(parent, PCI_DEVFN(0, fn));
if (!dev)
list_for_each_entry(dev, &parent->devices, bus_list) {
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
continue;
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
pci_dev_put(dev);
continue;
}
pci_configure_slot(dev);
pci_dev_put(dev);
}
pci_bus_add_devices(parent);
@ -89,9 +79,9 @@ int pciehp_configure_device(struct slot *p_slot)
int pciehp_unconfigure_device(struct slot *p_slot)
{
int ret, rc = 0;
int j;
u8 bctl = 0;
u8 presence = 0;
struct pci_dev *dev, *temp;
struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate;
u16 command;
struct controller *ctrl = p_slot->ctrl;
@ -102,33 +92,31 @@ int pciehp_unconfigure_device(struct slot *p_slot)
if (ret)
presence = 0;
for (j = 0; j < 8; j++) {
struct pci_dev *temp = pci_get_slot(parent, PCI_DEVFN(0, j));
if (!temp)
continue;
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
pci_dev_get(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
if (bctl & PCI_BRIDGE_CTL_VGA) {
ctrl_err(ctrl,
"Cannot remove display device %s\n",
pci_name(temp));
pci_dev_put(temp);
pci_name(dev));
pci_dev_put(dev);
rc = -EINVAL;
break;
}
}
pci_stop_and_remove_bus_device(temp);
pci_stop_and_remove_bus_device(dev);
/*
* Ensure that no new Requests will be generated from
* the device.
*/
if (presence) {
pci_read_config_word(temp, PCI_COMMAND, &command);
pci_read_config_word(dev, PCI_COMMAND, &command);
command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
command |= PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(temp, PCI_COMMAND, command);
pci_write_config_word(dev, PCI_COMMAND, command);
}
pci_dev_put(temp);
pci_dev_put(dev);
}
return rc;

View File

@ -334,7 +334,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
struct slot *slot = bss_hotplug_slot->private;
struct pci_bus *new_bus = NULL;
struct pci_dev *dev;
int func, num_funcs;
int num_funcs;
int new_ppb = 0;
int rc;
char *ssdt = NULL;
@ -381,29 +381,26 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
* to the Linux PCI interface and tell the drivers
* about them.
*/
for (func = 0; func < num_funcs; func++) {
dev = pci_get_slot(slot->pci_bus,
PCI_DEVFN(slot->device_num + 1,
PCI_FUNC(func)));
if (dev) {
/* Need to do slot fixup on PPB before fixup of children
* (PPB's pcidev_info needs to be in pcidev_info list
* before child's SN_PCIDEV_INFO() call to setup
* pdi_host_pcidev_info).
*/
pcibios_fixup_device_resources(dev);
if (SN_ACPI_BASE_SUPPORT())
sn_acpi_slot_fixup(dev);
else
sn_io_slot_fixup(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
pci_hp_add_bridge(dev);
if (dev->subordinate) {
new_bus = dev->subordinate;
new_ppb = 1;
}
list_for_each_entry(dev, &slot->pci_bus->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
continue;
/* Need to do slot fixup on PPB before fixup of children
* (PPB's pcidev_info needs to be in pcidev_info list
* before child's SN_PCIDEV_INFO() call to setup
* pdi_host_pcidev_info).
*/
pcibios_fixup_device_resources(dev);
if (SN_ACPI_BASE_SUPPORT())
sn_acpi_slot_fixup(dev);
else
sn_io_slot_fixup(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
pci_hp_add_bridge(dev);
if (dev->subordinate) {
new_bus = dev->subordinate;
new_ppb = 1;
}
pci_dev_put(dev);
}
}
@ -481,8 +478,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
{
struct slot *slot = bss_hotplug_slot->private;
struct pci_dev *dev;
int func;
struct pci_dev *dev, *temp;
int rc;
acpi_owner_id ssdt_id = 0;
@ -542,15 +538,14 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
}
/* Free the SN resources assigned to the Linux device.*/
for (func = 0; func < 8; func++) {
dev = pci_get_slot(slot->pci_bus,
PCI_DEVFN(slot->device_num + 1,
PCI_FUNC(func)));
if (dev) {
sn_bus_free_data(dev);
pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
continue;
pci_dev_get(dev);
sn_bus_free_data(dev);
pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
/* Remove the SSDT for the slot from the ACPI namespace */

View File

@ -40,7 +40,7 @@ int __ref shpchp_configure_device(struct slot *p_slot)
struct controller *ctrl = p_slot->ctrl;
struct pci_dev *bridge = ctrl->pci_dev;
struct pci_bus *parent = bridge->subordinate;
int num, fn;
int num;
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
if (dev) {
@ -57,24 +57,20 @@ int __ref shpchp_configure_device(struct slot *p_slot)
return -ENODEV;
}
for (fn = 0; fn < 8; fn++) {
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
if (!dev)
list_for_each_entry(dev, &parent->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != p_slot->device)
continue;
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS))
pci_hp_add_bridge(dev);
pci_dev_put(dev);
}
pci_assign_unassigned_bridge_resources(bridge);
for (fn = 0; fn < 8; fn++) {
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
if (!dev)
list_for_each_entry(dev, &parent->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != p_slot->device)
continue;
pci_configure_slot(dev);
pci_dev_put(dev);
}
pci_bus_add_devices(parent);
@ -85,32 +81,32 @@ int __ref shpchp_configure_device(struct slot *p_slot)
int shpchp_unconfigure_device(struct slot *p_slot)
{
int rc = 0;
int j;
u8 bctl = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
struct pci_dev *dev, *temp;
struct controller *ctrl = p_slot->ctrl;
ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
__func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
for (j = 0; j < 8 ; j++) {
struct pci_dev *temp = pci_get_slot(parent,
(p_slot->device << 3) | j);
if (!temp)
list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != p_slot->device)
continue;
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
pci_dev_get(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
if (bctl & PCI_BRIDGE_CTL_VGA) {
ctrl_err(ctrl,
"Cannot remove display device %s\n",
pci_name(temp));
pci_dev_put(temp);
pci_name(dev));
pci_dev_put(dev);
rc = -EINVAL;
break;
}
}
pci_stop_and_remove_bus_device(temp);
pci_dev_put(temp);
pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev);
}
return rc;
}

View File

@ -2042,10 +2042,13 @@ void pci_free_cap_save_buffers(struct pci_dev *dev)
}
/**
* pci_enable_ari - enable ARI forwarding if hardware support it
* pci_configure_ari - enable or disable ARI forwarding
* @dev: the PCI device
*
* If @dev and its upstream bridge both support ARI, enable ARI in the
* bridge. Otherwise, disable ARI in the bridge.
*/
void pci_enable_ari(struct pci_dev *dev)
void pci_configure_ari(struct pci_dev *dev)
{
u32 cap;
struct pci_dev *bridge;
@ -2053,9 +2056,6 @@ void pci_enable_ari(struct pci_dev *dev)
if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
return;
if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI))
return;
bridge = dev->bus->self;
if (!bridge)
return;
@ -2064,8 +2064,15 @@ void pci_enable_ari(struct pci_dev *dev)
if (!(cap & PCI_EXP_DEVCAP2_ARI))
return;
pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI);
bridge->ari_enabled = 1;
if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) {
pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_ARI);
bridge->ari_enabled = 1;
} else {
pcie_capability_clear_word(bridge, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_ARI);
bridge->ari_enabled = 0;
}
}
/**

View File

@ -204,7 +204,7 @@ extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
extern int pci_resource_bar(struct pci_dev *dev, int resno,
enum pci_bar_type *type);
extern int pci_bus_add_child(struct pci_bus *bus);
extern void pci_enable_ari(struct pci_dev *dev);
extern void pci_configure_ari(struct pci_dev *dev);
/**
* pci_ari_enabled - query ARI forwarding status
* @bus: the PCI bus

View File

@ -1285,7 +1285,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_vpd_pci22_init(dev);
/* Alternative Routing-ID Forwarding */
pci_enable_ari(dev);
pci_configure_ari(dev);
/* Single Root I/O Virtualization */
pci_iov_init(dev);
@ -1348,31 +1348,31 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
}
EXPORT_SYMBOL(pci_scan_single_device);
static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn)
static unsigned next_fn(struct pci_bus *bus, struct pci_dev *dev, unsigned fn)
{
u16 cap;
unsigned pos, next_fn;
int pos;
u16 cap = 0;
unsigned next_fn;
if (!dev)
return 0;
if (pci_ari_enabled(bus)) {
if (!dev)
return 0;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
if (!pos)
return 0;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
if (!pos)
return 0;
pci_read_config_word(dev, pos + 4, &cap);
next_fn = cap >> 8;
if (next_fn <= fn)
return 0;
return next_fn;
}
pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap);
next_fn = PCI_ARI_CAP_NFN(cap);
if (next_fn <= fn)
return 0; /* protect against malformed list */
static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn)
{
return (fn + 1) % 8;
}
return next_fn;
}
/* dev may be NULL for non-contiguous multifunction devices */
if (!dev || dev->multifunction)
return (fn + 1) % 8;
static unsigned no_next_fn(struct pci_dev *dev, unsigned fn)
{
return 0;
}
@ -1405,7 +1405,6 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
{
unsigned fn, nr = 0;
struct pci_dev *dev;
unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn;
if (only_one_child(bus) && (devfn > 0))
return 0; /* Already scanned the entire slot */
@ -1416,12 +1415,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
if (!dev->is_added)
nr++;
if (pci_ari_enabled(bus))
next_fn = next_ari_fn;
else if (dev->multifunction)
next_fn = next_trad_fn;
for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
dev = pci_scan_single_device(bus, devfn + fn);
if (dev) {
if (!dev->is_added)