Merge remote-tracking branch 'pci/pri-changes' into x86/amd
This commit is contained in:
commit
5c11ad95b5
16 changed files with 269 additions and 105 deletions
|
@ -66,6 +66,24 @@ Description:
|
|||
re-discover previously removed devices.
|
||||
Depends on CONFIG_HOTPLUG.
|
||||
|
||||
What: /sys/bus/pci/devices/.../msi_irqs/
|
||||
Date: September, 2011
|
||||
Contact: Neil Horman <nhorman@tuxdriver.com>
|
||||
Description:
|
||||
The /sys/devices/.../msi_irqs directory contains a variable set
|
||||
of sub-directories, with each sub-directory being named after a
|
||||
corresponding msi irq vector allocated to that device. Each
|
||||
numbered sub-directory N contains attributes of that irq.
|
||||
Note that this directory is not created for device drivers which
|
||||
do not support msi irqs
|
||||
|
||||
What: /sys/bus/pci/devices/.../msi_irqs/<N>/mode
|
||||
Date: September 2011
|
||||
Contact: Neil Horman <nhorman@tuxdriver.com>
|
||||
Description:
|
||||
This attribute indicates the mode that the irq vector named by
|
||||
the parent directory is in (msi vs. msix)
|
||||
|
||||
What: /sys/bus/pci/devices/.../remove
|
||||
Date: January 2009
|
||||
Contact: Linux PCI developers <linux-pci@vger.kernel.org>
|
||||
|
|
|
@ -596,6 +596,13 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
|
|||
if (ACPI_SUCCESS(status)) {
|
||||
dev_info(root->bus->bridge,
|
||||
"ACPI _OSC control (0x%02x) granted\n", flags);
|
||||
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
|
||||
/*
|
||||
* We have ASPM control, but the FADT indicates
|
||||
* that it's unsupported. Clear it.
|
||||
*/
|
||||
pcie_clear_aspm(root->bus);
|
||||
}
|
||||
} else {
|
||||
dev_info(root->bus->bridge,
|
||||
"ACPI _OSC request failed (%s), "
|
||||
|
|
|
@ -174,21 +174,22 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
|
|||
u32 max_requests;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
|
||||
if ((control & PCI_PRI_ENABLE) || !(status & PCI_PRI_STATUS_STOPPED))
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
|
||||
if ((control & PCI_PRI_CTRL_ENABLE) ||
|
||||
!(status & PCI_PRI_STATUS_STOPPED))
|
||||
return -EBUSY;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ_OFF, &max_requests);
|
||||
pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
|
||||
reqs = min(max_requests, reqs);
|
||||
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ_OFF, reqs);
|
||||
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
|
||||
|
||||
control |= PCI_PRI_ENABLE;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
|
||||
control |= PCI_PRI_CTRL_ENABLE;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -205,13 +206,13 @@ void pci_disable_pri(struct pci_dev *pdev)
|
|||
u16 control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
control &= ~PCI_PRI_ENABLE;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
control &= ~PCI_PRI_CTRL_ENABLE;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_disable_pri);
|
||||
|
||||
|
@ -226,13 +227,13 @@ bool pci_pri_enabled(struct pci_dev *pdev)
|
|||
u16 control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return false;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
|
||||
return (control & PCI_PRI_ENABLE) ? true : false;
|
||||
return (control & PCI_PRI_CTRL_ENABLE) ? true : false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_pri_enabled);
|
||||
|
||||
|
@ -248,17 +249,17 @@ int pci_reset_pri(struct pci_dev *pdev)
|
|||
u16 control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
if (control & PCI_PRI_ENABLE)
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
if (control & PCI_PRI_CTRL_ENABLE)
|
||||
return -EBUSY;
|
||||
|
||||
control |= PCI_PRI_RESET;
|
||||
control |= PCI_PRI_CTRL_RESET;
|
||||
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -281,14 +282,14 @@ bool pci_pri_stopped(struct pci_dev *pdev)
|
|||
u16 control, status;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return true;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
|
||||
|
||||
if (control & PCI_PRI_ENABLE)
|
||||
if (control & PCI_PRI_CTRL_ENABLE)
|
||||
return false;
|
||||
|
||||
return (status & PCI_PRI_STATUS_STOPPED) ? true : false;
|
||||
|
@ -310,15 +311,15 @@ int pci_pri_status(struct pci_dev *pdev)
|
|||
u16 status, control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
|
||||
|
||||
/* Stopped bit is undefined when enable == 1, so clear it */
|
||||
if (control & PCI_PRI_ENABLE)
|
||||
if (control & PCI_PRI_CTRL_ENABLE)
|
||||
status &= ~PCI_PRI_STATUS_STOPPED;
|
||||
|
||||
return status;
|
||||
|
@ -341,25 +342,25 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
|
|||
u16 control, supported;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CTRL, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
|
||||
|
||||
if (!(supported & PCI_PASID_ENABLE))
|
||||
if (control & PCI_PASID_CTRL_ENABLE)
|
||||
return -EINVAL;
|
||||
|
||||
supported &= PCI_PASID_EXEC | PCI_PASID_PRIV;
|
||||
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
|
||||
|
||||
/* User wants to enable anything unsupported? */
|
||||
if ((supported & features) != features)
|
||||
return -EINVAL;
|
||||
|
||||
control = PCI_PASID_ENABLE | features;
|
||||
control = PCI_PASID_CTRL_ENABLE | features;
|
||||
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -375,11 +376,11 @@ void pci_disable_pasid(struct pci_dev *pdev)
|
|||
u16 control = 0;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_disable_pasid);
|
||||
|
||||
|
@ -390,22 +391,21 @@ EXPORT_SYMBOL_GPL(pci_disable_pasid);
|
|||
* Returns a negative value when no PASI capability is present.
|
||||
* Otherwise is returns a bitmask with supported features. Current
|
||||
* features reported are:
|
||||
* PCI_PASID_ENABLE - PASID capability can be enabled
|
||||
* PCI_PASID_EXEC - Execute permission supported
|
||||
* PCI_PASID_PRIV - Priviledged mode supported
|
||||
* PCI_PASID_CAP_EXEC - Execute permission supported
|
||||
* PCI_PASID_CAP_PRIV - Priviledged mode supported
|
||||
*/
|
||||
int pci_pasid_features(struct pci_dev *pdev)
|
||||
{
|
||||
u16 supported;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
|
||||
|
||||
supported &= PCI_PASID_ENABLE | PCI_PASID_EXEC | PCI_PASID_PRIV;
|
||||
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
@ -425,11 +425,11 @@ int pci_max_pasids(struct pci_dev *pdev)
|
|||
u16 supported;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
|
||||
|
||||
supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
|
||||
|
||||
|
|
|
@ -467,7 +467,7 @@ static int add_bridge(acpi_handle handle)
|
|||
* granted by the BIOS for it.
|
||||
*/
|
||||
root = acpi_pci_find_root(handle);
|
||||
if (root && (root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL))
|
||||
if (root && (root->osc_control_set & OSC_PCI_NATIVE_HOTPLUG))
|
||||
return -ENODEV;
|
||||
|
||||
/* if the bridge doesn't have _STA, we assume it is always there */
|
||||
|
@ -1395,7 +1395,7 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|||
if (!root)
|
||||
return AE_OK;
|
||||
|
||||
if (root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)
|
||||
if (root->osc_control_set & OSC_PCI_NATIVE_HOTPLUG)
|
||||
return AE_OK;
|
||||
|
||||
(*count)++;
|
||||
|
|
|
@ -45,7 +45,6 @@ extern int pciehp_poll_time;
|
|||
extern int pciehp_debug;
|
||||
extern int pciehp_force;
|
||||
extern struct workqueue_struct *pciehp_wq;
|
||||
extern struct workqueue_struct *pciehp_ordered_wq;
|
||||
|
||||
#define dbg(format, arg...) \
|
||||
do { \
|
||||
|
|
|
@ -43,7 +43,6 @@ int pciehp_poll_mode;
|
|||
int pciehp_poll_time;
|
||||
int pciehp_force;
|
||||
struct workqueue_struct *pciehp_wq;
|
||||
struct workqueue_struct *pciehp_ordered_wq;
|
||||
|
||||
#define DRIVER_VERSION "0.4"
|
||||
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
|
||||
|
@ -345,18 +344,11 @@ static int __init pcied_init(void)
|
|||
if (!pciehp_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
pciehp_ordered_wq = alloc_ordered_workqueue("pciehp_ordered", 0);
|
||||
if (!pciehp_ordered_wq) {
|
||||
destroy_workqueue(pciehp_wq);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pciehp_firmware_init();
|
||||
retval = pcie_port_service_register(&hpdriver_portdrv);
|
||||
dbg("pcie_port_service_register = %d\n", retval);
|
||||
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
|
||||
if (retval) {
|
||||
destroy_workqueue(pciehp_ordered_wq);
|
||||
destroy_workqueue(pciehp_wq);
|
||||
dbg("Failure to register service\n");
|
||||
}
|
||||
|
@ -366,9 +358,8 @@ static int __init pcied_init(void)
|
|||
static void __exit pcied_cleanup(void)
|
||||
{
|
||||
dbg("unload_pciehpd()\n");
|
||||
destroy_workqueue(pciehp_ordered_wq);
|
||||
destroy_workqueue(pciehp_wq);
|
||||
pcie_port_service_unregister(&hpdriver_portdrv);
|
||||
destroy_workqueue(pciehp_wq);
|
||||
info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -344,7 +344,7 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
|
|||
kfree(info);
|
||||
goto out;
|
||||
}
|
||||
queue_work(pciehp_ordered_wq, &info->work);
|
||||
queue_work(pciehp_wq, &info->work);
|
||||
out:
|
||||
mutex_unlock(&p_slot->lock);
|
||||
}
|
||||
|
@ -439,7 +439,7 @@ static void handle_surprise_event(struct slot *p_slot)
|
|||
else
|
||||
p_slot->state = POWERON_STATE;
|
||||
|
||||
queue_work(pciehp_ordered_wq, &info->work);
|
||||
queue_work(pciehp_wq, &info->work);
|
||||
}
|
||||
|
||||
static void interrupt_event_handler(struct work_struct *work)
|
||||
|
|
|
@ -806,7 +806,6 @@ static void pcie_cleanup_slot(struct controller *ctrl)
|
|||
struct slot *slot = ctrl->slot;
|
||||
cancel_delayed_work(&slot->work);
|
||||
flush_workqueue(pciehp_wq);
|
||||
flush_workqueue(pciehp_ordered_wq);
|
||||
kfree(slot);
|
||||
}
|
||||
|
||||
|
|
|
@ -323,6 +323,8 @@ static void free_msi_irqs(struct pci_dev *dev)
|
|||
if (list_is_last(&entry->list, &dev->msi_list))
|
||||
iounmap(entry->mask_base);
|
||||
}
|
||||
kobject_del(&entry->kobj);
|
||||
kobject_put(&entry->kobj);
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
|
@ -403,6 +405,98 @@ void pci_restore_msi_state(struct pci_dev *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pci_restore_msi_state);
|
||||
|
||||
|
||||
#define to_msi_attr(obj) container_of(obj, struct msi_attribute, attr)
|
||||
#define to_msi_desc(obj) container_of(obj, struct msi_desc, kobj)
|
||||
|
||||
struct msi_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct msi_desc *entry, struct msi_attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct msi_desc *entry, struct msi_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
};
|
||||
|
||||
static ssize_t show_msi_mode(struct msi_desc *entry, struct msi_attribute *atr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", entry->msi_attrib.is_msix ? "msix" : "msi");
|
||||
}
|
||||
|
||||
static ssize_t msi_irq_attr_show(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
struct msi_attribute *attribute = to_msi_attr(attr);
|
||||
struct msi_desc *entry = to_msi_desc(kobj);
|
||||
|
||||
if (!attribute->show)
|
||||
return -EIO;
|
||||
|
||||
return attribute->show(entry, attribute, buf);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops msi_irq_sysfs_ops = {
|
||||
.show = msi_irq_attr_show,
|
||||
};
|
||||
|
||||
static struct msi_attribute mode_attribute =
|
||||
__ATTR(mode, S_IRUGO, show_msi_mode, NULL);
|
||||
|
||||
|
||||
struct attribute *msi_irq_default_attrs[] = {
|
||||
&mode_attribute.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
void msi_kobj_release(struct kobject *kobj)
|
||||
{
|
||||
struct msi_desc *entry = to_msi_desc(kobj);
|
||||
|
||||
pci_dev_put(entry->dev);
|
||||
}
|
||||
|
||||
static struct kobj_type msi_irq_ktype = {
|
||||
.release = msi_kobj_release,
|
||||
.sysfs_ops = &msi_irq_sysfs_ops,
|
||||
.default_attrs = msi_irq_default_attrs,
|
||||
};
|
||||
|
||||
static int populate_msi_sysfs(struct pci_dev *pdev)
|
||||
{
|
||||
struct msi_desc *entry;
|
||||
struct kobject *kobj;
|
||||
int ret;
|
||||
int count = 0;
|
||||
|
||||
pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj);
|
||||
if (!pdev->msi_kset)
|
||||
return -ENOMEM;
|
||||
|
||||
list_for_each_entry(entry, &pdev->msi_list, list) {
|
||||
kobj = &entry->kobj;
|
||||
kobj->kset = pdev->msi_kset;
|
||||
pci_dev_get(pdev);
|
||||
ret = kobject_init_and_add(kobj, &msi_irq_ktype, NULL,
|
||||
"%u", entry->irq);
|
||||
if (ret)
|
||||
goto out_unroll;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_unroll:
|
||||
list_for_each_entry(entry, &pdev->msi_list, list) {
|
||||
if (!count)
|
||||
break;
|
||||
kobject_del(&entry->kobj);
|
||||
kobject_put(&entry->kobj);
|
||||
count--;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* msi_capability_init - configure device's MSI capability structure
|
||||
* @dev: pointer to the pci_dev data structure of MSI device function
|
||||
|
@ -454,6 +548,13 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = populate_msi_sysfs(dev);
|
||||
if (ret) {
|
||||
msi_mask_irq(entry, mask, ~mask);
|
||||
free_msi_irqs(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set MSI enabled bits */
|
||||
pci_intx_for_msi(dev, 0);
|
||||
msi_set_enable(dev, pos, 1);
|
||||
|
@ -574,6 +675,12 @@ static int msix_capability_init(struct pci_dev *dev,
|
|||
|
||||
msix_program_entries(dev, entries);
|
||||
|
||||
ret = populate_msi_sysfs(dev);
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set MSI-X enabled bits and unmask the function */
|
||||
pci_intx_for_msi(dev, 0);
|
||||
dev->msix_enabled = 1;
|
||||
|
@ -732,6 +839,8 @@ void pci_disable_msi(struct pci_dev *dev)
|
|||
|
||||
pci_msi_shutdown(dev);
|
||||
free_msi_irqs(dev);
|
||||
kset_unregister(dev->msi_kset);
|
||||
dev->msi_kset = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_disable_msi);
|
||||
|
||||
|
@ -830,6 +939,8 @@ void pci_disable_msix(struct pci_dev *dev)
|
|||
|
||||
pci_msix_shutdown(dev);
|
||||
free_msi_irqs(dev);
|
||||
kset_unregister(dev->msi_kset);
|
||||
dev->msi_kset = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_disable_msix);
|
||||
|
||||
|
@ -870,5 +981,15 @@ EXPORT_SYMBOL(pci_msi_enabled);
|
|||
|
||||
void pci_msi_init_pci_dev(struct pci_dev *dev)
|
||||
{
|
||||
int pos;
|
||||
INIT_LIST_HEAD(&dev->msi_list);
|
||||
|
||||
/* Disable the msi hardware to avoid screaming interrupts
|
||||
* during boot. This is the power on reset default so
|
||||
* usually this should be a noop.
|
||||
*/
|
||||
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
|
||||
if (pos)
|
||||
msi_set_enable(dev, pos, 0);
|
||||
msix_set_enable(dev, 0);
|
||||
}
|
||||
|
|
|
@ -45,16 +45,20 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
|
|||
{
|
||||
struct pci_dev *pci_dev = context;
|
||||
|
||||
if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
|
||||
if (event != ACPI_NOTIFY_DEVICE_WAKE || !pci_dev)
|
||||
return;
|
||||
|
||||
if (!pci_dev->pm_cap || !pci_dev->pme_support
|
||||
|| pci_check_pme_status(pci_dev)) {
|
||||
if (pci_dev->pme_poll)
|
||||
pci_dev->pme_poll = false;
|
||||
|
||||
pci_wakeup_event(pci_dev);
|
||||
pci_check_pme_status(pci_dev);
|
||||
pm_runtime_resume(&pci_dev->dev);
|
||||
}
|
||||
|
||||
if (pci_dev->subordinate)
|
||||
pci_pme_wakeup_bus(pci_dev->subordinate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -395,7 +399,6 @@ static int __init acpi_pci_init(void)
|
|||
|
||||
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
|
||||
printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
|
||||
pcie_clear_aspm();
|
||||
pcie_no_aspm();
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ struct pcie_link_state {
|
|||
struct aspm_latency acceptable[8];
|
||||
};
|
||||
|
||||
static int aspm_disabled, aspm_force, aspm_clear_state;
|
||||
static int aspm_disabled, aspm_force;
|
||||
static bool aspm_support_enabled = true;
|
||||
static DEFINE_MUTEX(aspm_lock);
|
||||
static LIST_HEAD(link_list);
|
||||
|
@ -500,9 +500,6 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
|
|||
int pos;
|
||||
u32 reg32;
|
||||
|
||||
if (aspm_clear_state)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Some functions in a slot might not all be PCIe functions,
|
||||
* very strange. Disable ASPM for the whole slot
|
||||
|
@ -574,9 +571,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
|||
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
|
||||
return;
|
||||
|
||||
if (aspm_disabled && !aspm_clear_state)
|
||||
return;
|
||||
|
||||
/* VIA has a strange chipset, root port is under a bridge */
|
||||
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
|
||||
pdev->bus->self)
|
||||
|
@ -608,7 +602,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
|||
* the BIOS's expectation, we'll do so once pci_enable_device() is
|
||||
* called.
|
||||
*/
|
||||
if (aspm_policy != POLICY_POWERSAVE || aspm_clear_state) {
|
||||
if (aspm_policy != POLICY_POWERSAVE) {
|
||||
pcie_config_aspm_path(link);
|
||||
pcie_set_clkpm(link, policy_to_clkpm_state(link));
|
||||
}
|
||||
|
@ -649,8 +643,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
|
|||
struct pci_dev *parent = pdev->bus->self;
|
||||
struct pcie_link_state *link, *root, *parent_link;
|
||||
|
||||
if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
|
||||
!parent || !parent->link_state)
|
||||
if (!pci_is_pcie(pdev) || !parent || !parent->link_state)
|
||||
return;
|
||||
if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
|
||||
(parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
|
||||
|
@ -734,13 +727,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
|
|||
* pci_disable_link_state - disable pci device's link state, so the link will
|
||||
* never enter specific states
|
||||
*/
|
||||
static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
|
||||
static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem,
|
||||
bool force)
|
||||
{
|
||||
struct pci_dev *parent = pdev->bus->self;
|
||||
struct pcie_link_state *link;
|
||||
|
||||
if (aspm_disabled || !pci_is_pcie(pdev))
|
||||
if (aspm_disabled && !force)
|
||||
return;
|
||||
|
||||
if (!pci_is_pcie(pdev))
|
||||
return;
|
||||
|
||||
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
|
||||
parent = pdev;
|
||||
|
@ -768,16 +766,31 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
|
|||
|
||||
void pci_disable_link_state_locked(struct pci_dev *pdev, int state)
|
||||
{
|
||||
__pci_disable_link_state(pdev, state, false);
|
||||
__pci_disable_link_state(pdev, state, false, false);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_disable_link_state_locked);
|
||||
|
||||
void pci_disable_link_state(struct pci_dev *pdev, int state)
|
||||
{
|
||||
__pci_disable_link_state(pdev, state, true);
|
||||
__pci_disable_link_state(pdev, state, true, false);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_disable_link_state);
|
||||
|
||||
void pcie_clear_aspm(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_dev *child;
|
||||
|
||||
/*
|
||||
* Clear any ASPM setup that the firmware has carried out on this bus
|
||||
*/
|
||||
list_for_each_entry(child, &bus->devices, bus_list) {
|
||||
__pci_disable_link_state(child, PCIE_LINK_STATE_L0S |
|
||||
PCIE_LINK_STATE_L1 |
|
||||
PCIE_LINK_STATE_CLKPM,
|
||||
false, true);
|
||||
}
|
||||
}
|
||||
|
||||
static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
int i;
|
||||
|
@ -935,6 +948,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
|
|||
static int __init pcie_aspm_disable(char *str)
|
||||
{
|
||||
if (!strcmp(str, "off")) {
|
||||
aspm_policy = POLICY_DEFAULT;
|
||||
aspm_disabled = 1;
|
||||
aspm_support_enabled = false;
|
||||
printk(KERN_INFO "PCIe ASPM is disabled\n");
|
||||
|
@ -947,16 +961,18 @@ static int __init pcie_aspm_disable(char *str)
|
|||
|
||||
__setup("pcie_aspm=", pcie_aspm_disable);
|
||||
|
||||
void pcie_clear_aspm(void)
|
||||
{
|
||||
if (!aspm_force)
|
||||
aspm_clear_state = 1;
|
||||
}
|
||||
|
||||
void pcie_no_aspm(void)
|
||||
{
|
||||
if (!aspm_force)
|
||||
/*
|
||||
* Disabling ASPM is intended to prevent the kernel from modifying
|
||||
* existing hardware state, not to clear existing state. To that end:
|
||||
* (a) set policy to POLICY_DEFAULT in order to avoid changing state
|
||||
* (b) prevent userspace from changing policy
|
||||
*/
|
||||
if (!aspm_force) {
|
||||
aspm_policy = POLICY_DEFAULT;
|
||||
aspm_disabled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -302,6 +302,10 @@ extern bool osc_sb_apei_support_acked;
|
|||
OSC_PCI_EXPRESS_PME_CONTROL | \
|
||||
OSC_PCI_EXPRESS_AER_CONTROL | \
|
||||
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
|
||||
|
||||
#define OSC_PCI_NATIVE_HOTPLUG (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \
|
||||
OSC_SHPC_NATIVE_HP_CONTROL)
|
||||
|
||||
extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
|
||||
u32 *mask, u32 req);
|
||||
extern void acpi_early_init(void);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef LINUX_MSI_H
|
||||
#define LINUX_MSI_H
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
struct msi_msg {
|
||||
|
@ -44,6 +45,8 @@ struct msi_desc {
|
|||
|
||||
/* Last set MSI message */
|
||||
struct msi_msg msg;
|
||||
|
||||
struct kobject kobj;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -29,7 +29,7 @@ extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
|
|||
extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
|
||||
extern void pci_disable_link_state(struct pci_dev *pdev, int state);
|
||||
extern void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
|
||||
extern void pcie_clear_aspm(void);
|
||||
extern void pcie_clear_aspm(struct pci_bus *bus);
|
||||
extern void pcie_no_aspm(void);
|
||||
#else
|
||||
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
|
||||
|
@ -47,7 +47,7 @@ static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
|
|||
static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
|
||||
{
|
||||
}
|
||||
static inline void pcie_clear_aspm(void)
|
||||
static inline void pcie_clear_aspm(struct pci_bus *bus)
|
||||
{
|
||||
}
|
||||
static inline void pcie_no_aspm(void)
|
||||
|
|
|
@ -336,6 +336,7 @@ struct pci_dev {
|
|||
struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
struct list_head msi_list;
|
||||
struct kset *msi_kset;
|
||||
#endif
|
||||
struct pci_vpd *vpd;
|
||||
#ifdef CONFIG_PCI_ATS
|
||||
|
|
|
@ -537,7 +537,9 @@
|
|||
#define PCI_EXT_CAP_ID_ARI 14
|
||||
#define PCI_EXT_CAP_ID_ATS 15
|
||||
#define PCI_EXT_CAP_ID_SRIOV 16
|
||||
#define PCI_EXT_CAP_ID_PRI 19
|
||||
#define PCI_EXT_CAP_ID_LTR 24
|
||||
#define PCI_EXT_CAP_ID_PASID 27
|
||||
|
||||
/* Advanced Error Reporting */
|
||||
#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */
|
||||
|
@ -664,24 +666,24 @@
|
|||
#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */
|
||||
|
||||
/* Page Request Interface */
|
||||
#define PCI_PRI_CAP 0x13 /* PRI capability ID */
|
||||
#define PCI_PRI_CONTROL_OFF 0x04 /* Offset of control register */
|
||||
#define PCI_PRI_STATUS_OFF 0x06 /* Offset of status register */
|
||||
#define PCI_PRI_ENABLE 0x0001 /* Enable mask */
|
||||
#define PCI_PRI_RESET 0x0002 /* Reset bit mask */
|
||||
#define PCI_PRI_STATUS_RF 0x0001 /* Request Failure */
|
||||
#define PCI_PRI_STATUS_UPRGI 0x0002 /* Unexpected PRG index */
|
||||
#define PCI_PRI_STATUS_STOPPED 0x0100 /* PRI Stopped */
|
||||
#define PCI_PRI_MAX_REQ_OFF 0x08 /* Cap offset for max reqs supported */
|
||||
#define PCI_PRI_ALLOC_REQ_OFF 0x0c /* Cap offset for max reqs allowed */
|
||||
#define PCI_PRI_CTRL 0x04 /* PRI control register */
|
||||
#define PCI_PRI_CTRL_ENABLE 0x01 /* Enable */
|
||||
#define PCI_PRI_CTRL_RESET 0x02 /* Reset */
|
||||
#define PCI_PRI_STATUS 0x06 /* PRI status register */
|
||||
#define PCI_PRI_STATUS_RF 0x001 /* Response Failure */
|
||||
#define PCI_PRI_STATUS_UPRGI 0x002 /* Unexpected PRG index */
|
||||
#define PCI_PRI_STATUS_STOPPED 0x100 /* PRI Stopped */
|
||||
#define PCI_PRI_MAX_REQ 0x08 /* PRI max reqs supported */
|
||||
#define PCI_PRI_ALLOC_REQ 0x0c /* PRI max reqs allowed */
|
||||
|
||||
/* PASID capability */
|
||||
#define PCI_PASID_CAP 0x1b /* PASID capability ID */
|
||||
#define PCI_PASID_CAP_OFF 0x04 /* PASID feature register */
|
||||
#define PCI_PASID_CONTROL_OFF 0x06 /* PASID control register */
|
||||
#define PCI_PASID_ENABLE 0x01 /* Enable/Supported bit */
|
||||
#define PCI_PASID_EXEC 0x02 /* Exec permissions Enable/Supported */
|
||||
#define PCI_PASID_PRIV 0x04 /* Priviledge Mode Enable/Support */
|
||||
#define PCI_PASID_CAP 0x04 /* PASID feature register */
|
||||
#define PCI_PASID_CAP_EXEC 0x02 /* Exec permissions Supported */
|
||||
#define PCI_PASID_CAP_PRIV 0x04 /* Priviledge Mode Supported */
|
||||
#define PCI_PASID_CTRL 0x06 /* PASID control register */
|
||||
#define PCI_PASID_CTRL_ENABLE 0x01 /* Enable bit */
|
||||
#define PCI_PASID_CTRL_EXEC 0x02 /* Exec permissions Enable */
|
||||
#define PCI_PASID_CTRL_PRIV 0x04 /* Priviledge Mode Enable */
|
||||
|
||||
/* Single Root I/O Virtualization */
|
||||
#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */
|
||||
|
|
Loading…
Reference in a new issue