mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-13 00:42:40 -04:00
Merge branch 'slot' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci into v7.3/vfio/s390x-pci-error-recovery
PCI dependencies from shared branch supporting vfio-pci error recovery on s390x. Signed-off-by: Alex Williamson <alex@shazbot.org>
This commit is contained in:
@@ -808,7 +808,7 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
|
||||
if (dn->child && PCI_DN(dn->child))
|
||||
php_slot->slot_no = PCI_SLOT(PCI_DN(dn->child)->devfn);
|
||||
else
|
||||
php_slot->slot_no = -1; /* Placeholder slot */
|
||||
php_slot->slot_no = PCI_SLOT_PLACEHOLDER; /* Placeholder slot */
|
||||
|
||||
kref_init(&php_slot->kref);
|
||||
php_slot->state = PNV_PHP_STATE_INITIALIZED;
|
||||
|
||||
@@ -84,7 +84,7 @@ int rpaphp_register_slot(struct slot *slot)
|
||||
struct hotplug_slot *php_slot = &slot->hotplug_slot;
|
||||
u32 my_index;
|
||||
int retval;
|
||||
int slotno = -1;
|
||||
int slotno = PCI_SLOT_PLACEHOLDER;
|
||||
|
||||
dbg("%s registering slot:path[%pOF] index[%x], name[%s] pdomain[%x] type[%d]\n",
|
||||
__func__, slot->dn, slot->index, slot->name,
|
||||
|
||||
@@ -870,6 +870,7 @@ void __pci_restore_msix_state(struct pci_dev *dev)
|
||||
{
|
||||
struct msi_desc *entry;
|
||||
bool write_msg;
|
||||
u16 cmd;
|
||||
|
||||
if (!dev->msix_enabled)
|
||||
return;
|
||||
@@ -879,6 +880,14 @@ void __pci_restore_msix_state(struct pci_dev *dev)
|
||||
pci_msix_clear_and_set_ctrl(dev, 0,
|
||||
PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
|
||||
|
||||
/*
|
||||
* The restored device state may not have Memory Space enabled.
|
||||
* Since the MSI-X Table and PBA are in Memory Space, enable it
|
||||
* while restoring them.
|
||||
*/
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
|
||||
|
||||
write_msg = arch_restore_msi_irqs(dev);
|
||||
|
||||
scoped_guard (msi_descs_lock, &dev->dev) {
|
||||
@@ -889,6 +898,7 @@ void __pci_restore_msix_state(struct pci_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -713,6 +713,28 @@ u16 pci_find_dvsec_capability(struct pci_dev *dev, u16 vendor, u16 dvsec)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_find_dvsec_capability);
|
||||
|
||||
static bool pci_dev_config_accessible(struct pci_dev *dev, char *msg)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* If a device's config space is inaccessible, reads typically
|
||||
* return ~0. Since Device and Vendor ID are always ~0 for VFs,
|
||||
* check the Command and Status registers instead.
|
||||
*
|
||||
* N.B. This is racy because the device may become inaccessible
|
||||
* before the next access.
|
||||
*/
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &val);
|
||||
if (PCI_POSSIBLE_ERROR(val)) {
|
||||
pci_warn(dev, "Device config space inaccessible; unable to %s\n",
|
||||
msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_find_parent_resource - return resource region of parent bus of given
|
||||
* region
|
||||
@@ -4363,6 +4385,9 @@ int pcie_flr(struct pci_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!pci_dev_config_accessible(dev, "FLR"))
|
||||
return -ENOTTY;
|
||||
|
||||
if (!pci_wait_for_pending_transaction(dev))
|
||||
pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
|
||||
|
||||
@@ -4897,8 +4922,9 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, bool probe)
|
||||
|
||||
static int pci_dev_reset_slot_function(struct pci_dev *dev, bool probe)
|
||||
{
|
||||
if (dev->multifunction || dev->subordinate || !dev->slot ||
|
||||
dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
|
||||
if (dev->subordinate || !dev->slot ||
|
||||
dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
|
||||
(dev->multifunction && !dev->slot->per_func_slot))
|
||||
return -ENOTTY;
|
||||
|
||||
return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
|
||||
@@ -5058,6 +5084,9 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)
|
||||
*/
|
||||
pci_set_power_state(dev, PCI_D0);
|
||||
|
||||
if (!pci_dev_config_accessible(dev, "save state"))
|
||||
return;
|
||||
|
||||
pci_save_state(dev);
|
||||
/*
|
||||
* Disable the device by clearing the Command register, except for
|
||||
|
||||
@@ -37,7 +37,7 @@ static const struct sysfs_ops pci_slot_sysfs_ops = {
|
||||
|
||||
static ssize_t address_read_file(struct pci_slot *slot, char *buf)
|
||||
{
|
||||
if (slot->number == 0xff)
|
||||
if (slot->number == PCI_SLOT_PLACEHOLDER)
|
||||
return sysfs_emit(buf, "%04x:%02x\n",
|
||||
pci_domain_nr(slot->bus),
|
||||
slot->bus->number);
|
||||
@@ -72,6 +72,23 @@ static ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf)
|
||||
return bus_speed_read(slot->bus->cur_bus_speed, buf);
|
||||
}
|
||||
|
||||
static bool pci_dev_matches_slot(struct pci_dev *dev, struct pci_slot *slot)
|
||||
{
|
||||
if (slot->per_func_slot)
|
||||
return dev->devfn == slot->number;
|
||||
|
||||
return slot->number == PCI_SLOT_ALL_DEVICES ||
|
||||
PCI_SLOT(dev->devfn) == slot->number;
|
||||
}
|
||||
|
||||
static bool pci_slot_enabled_per_func(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_S390))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void pci_slot_release(struct kobject *kobj)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
@@ -82,8 +99,7 @@ static void pci_slot_release(struct kobject *kobj)
|
||||
|
||||
down_read(&pci_bus_sem);
|
||||
list_for_each_entry(dev, &slot->bus->devices, bus_list)
|
||||
if (slot->number == PCI_SLOT_ALL_DEVICES ||
|
||||
PCI_SLOT(dev->devfn) == slot->number)
|
||||
if (pci_dev_matches_slot(dev, slot))
|
||||
dev->slot = NULL;
|
||||
up_read(&pci_bus_sem);
|
||||
|
||||
@@ -187,8 +203,7 @@ void pci_dev_assign_slot(struct pci_dev *dev)
|
||||
|
||||
mutex_lock(&pci_slot_mutex);
|
||||
list_for_each_entry(slot, &dev->bus->slots, list)
|
||||
if (slot->number == PCI_SLOT_ALL_DEVICES ||
|
||||
PCI_SLOT(dev->devfn) == slot->number)
|
||||
if (pci_dev_matches_slot(dev, slot))
|
||||
dev->slot = slot;
|
||||
mutex_unlock(&pci_slot_mutex);
|
||||
}
|
||||
@@ -210,7 +225,7 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
|
||||
/**
|
||||
* pci_create_slot - create or increment refcount for physical PCI slot
|
||||
* @parent: struct pci_bus of parent bridge
|
||||
* @slot_nr: PCI_SLOT(pci_dev->devfn), -1 for placeholder, or
|
||||
* @slot_nr: PCI_SLOT(pci_dev->devfn), PCI_SLOT_PLACEHOLDER for placeholder, or
|
||||
* PCI_SLOT_ALL_DEVICES
|
||||
* @name: user visible string presented in /sys/bus/pci/slots/<name>
|
||||
* @hotplug: set if caller is hotplug driver, NULL otherwise
|
||||
@@ -236,15 +251,16 @@ static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
|
||||
* In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify
|
||||
* a slot. There is one notable exception - pSeries (rpaphp), where the
|
||||
* @slot_nr cannot be determined until a device is actually inserted into
|
||||
* the slot. In this scenario, the caller may pass -1 for @slot_nr.
|
||||
* the slot. In this scenario, the caller may pass PCI_SLOT_PLACEHOLDER for @slot_nr.
|
||||
*
|
||||
* The following semantics are imposed when the caller passes @slot_nr ==
|
||||
* -1. First, we no longer check for an existing %struct pci_slot, as there
|
||||
* may be many slots with @slot_nr of -1. The other change in semantics is
|
||||
* user-visible, which is the 'address' parameter presented in sysfs will
|
||||
* consist solely of a dddd:bb tuple, where dddd is the PCI domain of the
|
||||
* %struct pci_bus and bb is the bus number. In other words, the devfn of
|
||||
* the 'placeholder' slot will not be displayed.
|
||||
* PCI_SLOT_PLACEHOLDER. First, we no longer check for an existing %struct
|
||||
* pci_slot, as there may be many slots with @slot_nr of
|
||||
* PCI_SLOT_PLACEHOLDER. The other change in semantics is user-visible,
|
||||
* which is the 'address' parameter presented in sysfs will consist solely
|
||||
* of a dddd:bb tuple, where dddd is the PCI domain of the %struct pci_bus
|
||||
* and bb is the bus number. In other words, the devfn of the 'placeholder'
|
||||
* slot will not be displayed.
|
||||
*
|
||||
* Bus-wide slots:
|
||||
* For PCIe hotplug, the physical slot encompasses the entire secondary
|
||||
@@ -267,7 +283,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
|
||||
|
||||
mutex_lock(&pci_slot_mutex);
|
||||
|
||||
if (slot_nr == -1)
|
||||
if (slot_nr == PCI_SLOT_PLACEHOLDER)
|
||||
goto placeholder;
|
||||
|
||||
/*
|
||||
@@ -298,6 +314,9 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
|
||||
slot->bus = pci_bus_get(parent);
|
||||
slot->number = slot_nr;
|
||||
|
||||
if (pci_slot_enabled_per_func())
|
||||
slot->per_func_slot = 1;
|
||||
|
||||
slot->kobj.kset = pci_slots_kset;
|
||||
|
||||
slot_name = make_slot_name(name);
|
||||
@@ -318,8 +337,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
|
||||
|
||||
down_read(&pci_bus_sem);
|
||||
list_for_each_entry(dev, &parent->devices, bus_list)
|
||||
if (slot_nr == PCI_SLOT_ALL_DEVICES ||
|
||||
PCI_SLOT(dev->devfn) == slot_nr)
|
||||
if (pci_dev_matches_slot(dev, slot))
|
||||
dev->slot = slot;
|
||||
up_read(&pci_bus_sem);
|
||||
|
||||
|
||||
@@ -79,14 +79,18 @@
|
||||
* and, if ARI Forwarding is enabled, functions may appear to be on multiple
|
||||
* devices.
|
||||
*/
|
||||
#define PCI_SLOT_ALL_DEVICES 0xfe
|
||||
#define PCI_SLOT_ALL_DEVICES 0xfeff
|
||||
|
||||
/* Used to identify a slot as a placeholder */
|
||||
#define PCI_SLOT_PLACEHOLDER 0xffff
|
||||
|
||||
/* pci_slot represents a physical slot */
|
||||
struct pci_slot {
|
||||
struct pci_bus *bus; /* Bus this slot is on */
|
||||
struct list_head list; /* Node in list of slots */
|
||||
struct hotplug_slot *hotplug; /* Hotplug info (move here) */
|
||||
unsigned char number; /* Device nr, or PCI_SLOT_ALL_DEVICES */
|
||||
u16 number; /* Device nr, or PCI_SLOT_ALL_DEVICES */
|
||||
unsigned int per_func_slot:1; /* Allow per function slot */
|
||||
struct kobject kobj;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user