Merge branches 'pci/hotplug', 'pci/iommu', 'pci/irq' and 'pci/virtualization' into next
* pci/hotplug: PCI: pciehp: Remove ignored MRL sensor interrupt events PCI: pciehp: Remove unused interrupt events PCI: pciehp: Handle invalid data when reading from non-existent devices PCI: Hold pci_slot_mutex while searching bus->slots list PCI: Protect pci_bus->slots with pci_slot_mutex, not pci_bus_sem PCI: pciehp: Simplify pcie_poll_cmd() PCI: Use "slot" and "pci_slot" for struct hotplug_slot and struct pci_slot * pci/iommu: PCI: Remove pci_ats_enabled() PCI: Stop caching ATS Invalidate Queue Depth PCI: Move ATS declarations to linux/pci.h so they're all together PCI: Clean up ATS error handling PCI: Use pci_physfn() rather than looking up physfn by hand PCI: Inline the ATS setup code into pci_ats_init() PCI: Rationalize pci_ats_queue_depth() error checking PCI: Reduce size of ATS structure elements PCI: Embed ATS info directly into struct pci_dev PCI: Allocate ATS struct during enumeration iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth * pci/irq: PCI: Kill off set_irq_flags() usage * pci/virtualization: PCI: Add ACS quirks for Intel I219-LM/V
This commit is contained in:
commit
1f408d5743
|
@ -126,7 +126,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
|
||||||
{
|
{
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
const char *type;
|
const char *type;
|
||||||
struct pci_slot *slot;
|
|
||||||
|
|
||||||
dev = pci_alloc_dev(bus);
|
dev = pci_alloc_dev(bus);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
|
@ -145,10 +144,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
|
||||||
dev->needs_freset = 0; /* pcie fundamental reset required */
|
dev->needs_freset = 0; /* pcie fundamental reset required */
|
||||||
set_pcie_port_type(dev);
|
set_pcie_port_type(dev);
|
||||||
|
|
||||||
list_for_each_entry(slot, &dev->bus->slots, list)
|
pci_dev_assign_slot(dev);
|
||||||
if (PCI_SLOT(dev->devfn) == slot->number)
|
|
||||||
dev->slot = slot;
|
|
||||||
|
|
||||||
dev->vendor = get_int_prop(node, "vendor-id", 0xffff);
|
dev->vendor = get_int_prop(node, "vendor-id", 0xffff);
|
||||||
dev->device = get_int_prop(node, "device-id", 0xffff);
|
dev->device = get_int_prop(node, "device-id", 0xffff);
|
||||||
dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
|
dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
|
||||||
|
|
|
@ -249,7 +249,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
|
||||||
struct pci_bus *bus, int devfn)
|
struct pci_bus *bus, int devfn)
|
||||||
{
|
{
|
||||||
struct dev_archdata *sd;
|
struct dev_archdata *sd;
|
||||||
struct pci_slot *slot;
|
|
||||||
struct platform_device *op;
|
struct platform_device *op;
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
const char *type;
|
const char *type;
|
||||||
|
@ -290,10 +289,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
|
||||||
dev->multifunction = 0; /* maybe a lie? */
|
dev->multifunction = 0; /* maybe a lie? */
|
||||||
set_pcie_port_type(dev);
|
set_pcie_port_type(dev);
|
||||||
|
|
||||||
list_for_each_entry(slot, &dev->bus->slots, list)
|
pci_dev_assign_slot(dev);
|
||||||
if (PCI_SLOT(dev->devfn) == slot->number)
|
|
||||||
dev->slot = slot;
|
|
||||||
|
|
||||||
dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
|
dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
|
||||||
dev->device = of_getintprop_default(node, "device-id", 0xffff);
|
dev->device = of_getintprop_default(node, "device-id", 0xffff);
|
||||||
dev->subsystem_vendor =
|
dev->subsystem_vendor =
|
||||||
|
|
|
@ -408,6 +408,10 @@ struct device_domain_info {
|
||||||
struct list_head global; /* link to global list */
|
struct list_head global; /* link to global list */
|
||||||
u8 bus; /* PCI bus number */
|
u8 bus; /* PCI bus number */
|
||||||
u8 devfn; /* PCI devfn number */
|
u8 devfn; /* PCI devfn number */
|
||||||
|
struct {
|
||||||
|
u8 enabled:1;
|
||||||
|
u8 qdep;
|
||||||
|
} ats; /* ATS state */
|
||||||
struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
|
struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
|
||||||
struct intel_iommu *iommu; /* IOMMU used by this device */
|
struct intel_iommu *iommu; /* IOMMU used by this device */
|
||||||
struct dmar_domain *domain; /* pointer to domain */
|
struct dmar_domain *domain; /* pointer to domain */
|
||||||
|
@ -1391,19 +1395,26 @@ iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu,
|
||||||
|
|
||||||
static void iommu_enable_dev_iotlb(struct device_domain_info *info)
|
static void iommu_enable_dev_iotlb(struct device_domain_info *info)
|
||||||
{
|
{
|
||||||
|
struct pci_dev *pdev;
|
||||||
|
|
||||||
if (!info || !dev_is_pci(info->dev))
|
if (!info || !dev_is_pci(info->dev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pci_enable_ats(to_pci_dev(info->dev), VTD_PAGE_SHIFT);
|
pdev = to_pci_dev(info->dev);
|
||||||
|
if (pci_enable_ats(pdev, VTD_PAGE_SHIFT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
info->ats.enabled = 1;
|
||||||
|
info->ats.qdep = pci_ats_queue_depth(pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iommu_disable_dev_iotlb(struct device_domain_info *info)
|
static void iommu_disable_dev_iotlb(struct device_domain_info *info)
|
||||||
{
|
{
|
||||||
if (!info->dev || !dev_is_pci(info->dev) ||
|
if (!info->ats.enabled)
|
||||||
!pci_ats_enabled(to_pci_dev(info->dev)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pci_disable_ats(to_pci_dev(info->dev));
|
pci_disable_ats(to_pci_dev(info->dev));
|
||||||
|
info->ats.enabled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
|
static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
|
||||||
|
@ -1415,16 +1426,11 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
|
||||||
|
|
||||||
spin_lock_irqsave(&device_domain_lock, flags);
|
spin_lock_irqsave(&device_domain_lock, flags);
|
||||||
list_for_each_entry(info, &domain->devices, link) {
|
list_for_each_entry(info, &domain->devices, link) {
|
||||||
struct pci_dev *pdev;
|
if (!info->ats.enabled)
|
||||||
if (!info->dev || !dev_is_pci(info->dev))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pdev = to_pci_dev(info->dev);
|
|
||||||
if (!pci_ats_enabled(pdev))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sid = info->bus << 8 | info->devfn;
|
sid = info->bus << 8 | info->devfn;
|
||||||
qdep = pci_ats_queue_depth(pdev);
|
qdep = info->ats.qdep;
|
||||||
qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
|
qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&device_domain_lock, flags);
|
spin_unlock_irqrestore(&device_domain_lock, flags);
|
||||||
|
@ -2272,6 +2278,8 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu,
|
||||||
|
|
||||||
info->bus = bus;
|
info->bus = bus;
|
||||||
info->devfn = devfn;
|
info->devfn = devfn;
|
||||||
|
info->ats.enabled = 0;
|
||||||
|
info->ats.qdep = 0;
|
||||||
info->dev = dev;
|
info->dev = dev;
|
||||||
info->domain = domain;
|
info->domain = domain;
|
||||||
info->iommu = iommu;
|
info->iommu = iommu;
|
||||||
|
|
|
@ -17,34 +17,15 @@
|
||||||
|
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
||||||
static int ats_alloc_one(struct pci_dev *dev, int ps)
|
void pci_ats_init(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
int pos;
|
int pos;
|
||||||
u16 cap;
|
|
||||||
struct pci_ats *ats;
|
|
||||||
|
|
||||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
|
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
|
||||||
if (!pos)
|
if (!pos)
|
||||||
return -ENODEV;
|
return;
|
||||||
|
|
||||||
ats = kzalloc(sizeof(*ats), GFP_KERNEL);
|
dev->ats_cap = pos;
|
||||||
if (!ats)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
ats->pos = pos;
|
|
||||||
ats->stu = ps;
|
|
||||||
pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
|
|
||||||
ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
|
|
||||||
PCI_ATS_MAX_QDEP;
|
|
||||||
dev->ats = ats;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ats_free_one(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
kfree(dev->ats);
|
|
||||||
dev->ats = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,43 +37,36 @@ static void ats_free_one(struct pci_dev *dev)
|
||||||
*/
|
*/
|
||||||
int pci_enable_ats(struct pci_dev *dev, int ps)
|
int pci_enable_ats(struct pci_dev *dev, int ps)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
u16 ctrl;
|
u16 ctrl;
|
||||||
|
struct pci_dev *pdev;
|
||||||
|
|
||||||
BUG_ON(dev->ats && dev->ats->is_enabled);
|
if (!dev->ats_cap)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (WARN_ON(dev->ats_enabled))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
if (ps < PCI_ATS_MIN_STU)
|
if (ps < PCI_ATS_MIN_STU)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (dev->is_physfn || dev->is_virtfn) {
|
/*
|
||||||
struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
|
* Note that enabling ATS on a VF fails unless it's already enabled
|
||||||
|
* with the same STU on the PF.
|
||||||
mutex_lock(&pdev->sriov->lock);
|
*/
|
||||||
if (pdev->ats)
|
|
||||||
rc = pdev->ats->stu == ps ? 0 : -EINVAL;
|
|
||||||
else
|
|
||||||
rc = ats_alloc_one(pdev, ps);
|
|
||||||
|
|
||||||
if (!rc)
|
|
||||||
pdev->ats->ref_cnt++;
|
|
||||||
mutex_unlock(&pdev->sriov->lock);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dev->is_physfn) {
|
|
||||||
rc = ats_alloc_one(dev, ps);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl = PCI_ATS_CTRL_ENABLE;
|
ctrl = PCI_ATS_CTRL_ENABLE;
|
||||||
if (!dev->is_virtfn)
|
if (dev->is_virtfn) {
|
||||||
ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
|
pdev = pci_physfn(dev);
|
||||||
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
|
if (pdev->ats_stu != ps)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
dev->ats->is_enabled = 1;
|
atomic_inc(&pdev->ats_ref_cnt); /* count enabled VFs */
|
||||||
|
} else {
|
||||||
|
dev->ats_stu = ps;
|
||||||
|
ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
|
||||||
|
}
|
||||||
|
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
||||||
|
|
||||||
|
dev->ats_enabled = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_enable_ats);
|
EXPORT_SYMBOL_GPL(pci_enable_ats);
|
||||||
|
@ -103,28 +77,25 @@ EXPORT_SYMBOL_GPL(pci_enable_ats);
|
||||||
*/
|
*/
|
||||||
void pci_disable_ats(struct pci_dev *dev)
|
void pci_disable_ats(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
|
struct pci_dev *pdev;
|
||||||
u16 ctrl;
|
u16 ctrl;
|
||||||
|
|
||||||
BUG_ON(!dev->ats || !dev->ats->is_enabled);
|
if (WARN_ON(!dev->ats_enabled))
|
||||||
|
return;
|
||||||
|
|
||||||
pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
|
if (atomic_read(&dev->ats_ref_cnt))
|
||||||
ctrl &= ~PCI_ATS_CTRL_ENABLE;
|
return; /* VFs still enabled */
|
||||||
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
|
|
||||||
|
|
||||||
dev->ats->is_enabled = 0;
|
if (dev->is_virtfn) {
|
||||||
|
pdev = pci_physfn(dev);
|
||||||
if (dev->is_physfn || dev->is_virtfn) {
|
atomic_dec(&pdev->ats_ref_cnt);
|
||||||
struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
|
|
||||||
|
|
||||||
mutex_lock(&pdev->sriov->lock);
|
|
||||||
pdev->ats->ref_cnt--;
|
|
||||||
if (!pdev->ats->ref_cnt)
|
|
||||||
ats_free_one(pdev);
|
|
||||||
mutex_unlock(&pdev->sriov->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev->is_physfn)
|
pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl);
|
||||||
ats_free_one(dev);
|
ctrl &= ~PCI_ATS_CTRL_ENABLE;
|
||||||
|
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
||||||
|
|
||||||
|
dev->ats_enabled = 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_disable_ats);
|
EXPORT_SYMBOL_GPL(pci_disable_ats);
|
||||||
|
|
||||||
|
@ -132,16 +103,13 @@ void pci_restore_ats_state(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
u16 ctrl;
|
u16 ctrl;
|
||||||
|
|
||||||
if (!pci_ats_enabled(dev))
|
if (!dev->ats_enabled)
|
||||||
return;
|
return;
|
||||||
if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS))
|
|
||||||
BUG();
|
|
||||||
|
|
||||||
ctrl = PCI_ATS_CTRL_ENABLE;
|
ctrl = PCI_ATS_CTRL_ENABLE;
|
||||||
if (!dev->is_virtfn)
|
if (!dev->is_virtfn)
|
||||||
ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
|
ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
|
||||||
|
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
||||||
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_restore_ats_state);
|
EXPORT_SYMBOL_GPL(pci_restore_ats_state);
|
||||||
|
|
||||||
|
@ -159,23 +127,16 @@ EXPORT_SYMBOL_GPL(pci_restore_ats_state);
|
||||||
*/
|
*/
|
||||||
int pci_ats_queue_depth(struct pci_dev *dev)
|
int pci_ats_queue_depth(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
int pos;
|
|
||||||
u16 cap;
|
u16 cap;
|
||||||
|
|
||||||
|
if (!dev->ats_cap)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (dev->is_virtfn)
|
if (dev->is_virtfn)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dev->ats)
|
pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
|
||||||
return dev->ats->qdep;
|
return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
|
|
||||||
if (!pos)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
|
|
||||||
|
|
||||||
return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
|
|
||||||
PCI_ATS_MAX_QDEP;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
|
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,6 @@ static int dra7xx_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
|
||||||
{
|
{
|
||||||
irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
|
irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
|
||||||
irq_set_chip_data(irq, domain->host_data);
|
irq_set_chip_data(irq, domain->host_data);
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,7 +196,6 @@ static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
|
||||||
irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
|
irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
|
||||||
handle_level_irq);
|
handle_level_irq);
|
||||||
irq_set_chip_data(irq, domain->host_data);
|
irq_set_chip_data(irq, domain->host_data);
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -277,7 +276,6 @@ static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
|
||||||
irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip,
|
irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip,
|
||||||
handle_level_irq);
|
handle_level_irq);
|
||||||
irq_set_chip_data(irq, d->host_data);
|
irq_set_chip_data(irq, d->host_data);
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1248,7 +1248,6 @@ static int tegra_msi_map(struct irq_domain *domain, unsigned int irq,
|
||||||
{
|
{
|
||||||
irq_set_chip_and_handler(irq, &tegra_msi_irq_chip, handle_simple_irq);
|
irq_set_chip_and_handler(irq, &tegra_msi_irq_chip, handle_simple_irq);
|
||||||
irq_set_chip_data(irq, domain->host_data);
|
irq_set_chip_data(irq, domain->host_data);
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
|
|
||||||
tegra_cpuidle_pcie_irqs_in_use();
|
tegra_cpuidle_pcie_irqs_in_use();
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,6 @@ static int xgene_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||||
irq_domain_set_info(domain, virq, msi_irq,
|
irq_domain_set_info(domain, virq, msi_irq,
|
||||||
&xgene_msi_bottom_irq_chip, domain->host_data,
|
&xgene_msi_bottom_irq_chip, domain->host_data,
|
||||||
handle_simple_irq, NULL, NULL);
|
handle_simple_irq, NULL, NULL);
|
||||||
set_irq_flags(virq, IRQF_VALID);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -350,7 +350,6 @@ static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
|
||||||
{
|
{
|
||||||
irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
|
irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
|
||||||
irq_set_chip_data(irq, domain->host_data);
|
irq_set_chip_data(irq, domain->host_data);
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -664,7 +664,6 @@ static int rcar_msi_map(struct irq_domain *domain, unsigned int irq,
|
||||||
{
|
{
|
||||||
irq_set_chip_and_handler(irq, &rcar_msi_irq_chip, handle_simple_irq);
|
irq_set_chip_and_handler(irq, &rcar_msi_irq_chip, handle_simple_irq);
|
||||||
irq_set_chip_data(irq, domain->host_data);
|
irq_set_chip_data(irq, domain->host_data);
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,7 +338,6 @@ static int xilinx_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
|
||||||
{
|
{
|
||||||
irq_set_chip_and_handler(irq, &xilinx_msi_irq_chip, handle_simple_irq);
|
irq_set_chip_and_handler(irq, &xilinx_msi_irq_chip, handle_simple_irq);
|
||||||
irq_set_chip_data(irq, domain->host_data);
|
irq_set_chip_data(irq, domain->host_data);
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -377,7 +376,6 @@ static int xilinx_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
|
||||||
{
|
{
|
||||||
irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
|
irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
|
||||||
irq_set_chip_data(irq, domain->host_data);
|
irq_set_chip_data(irq, domain->host_data);
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,12 +83,12 @@ GET_STATUS(attention_status, u8)
|
||||||
GET_STATUS(latch_status, u8)
|
GET_STATUS(latch_status, u8)
|
||||||
GET_STATUS(adapter_status, u8)
|
GET_STATUS(adapter_status, u8)
|
||||||
|
|
||||||
static ssize_t power_read_file(struct pci_slot *slot, char *buf)
|
static ssize_t power_read_file(struct pci_slot *pci_slot, char *buf)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
u8 value;
|
u8 value;
|
||||||
|
|
||||||
retval = get_power_status(slot->hotplug, &value);
|
retval = get_power_status(pci_slot->hotplug, &value);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -140,22 +140,22 @@ static struct pci_slot_attribute hotplug_slot_attr_power = {
|
||||||
.store = power_write_file
|
.store = power_write_file
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t attention_read_file(struct pci_slot *slot, char *buf)
|
static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
u8 value;
|
u8 value;
|
||||||
|
|
||||||
retval = get_attention_status(slot->hotplug, &value);
|
retval = get_attention_status(pci_slot->hotplug, &value);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", value);
|
return sprintf(buf, "%d\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t attention_write_file(struct pci_slot *slot, const char *buf,
|
static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
struct hotplug_slot_ops *ops = slot->hotplug->ops;
|
struct hotplug_slot_ops *ops = pci_slot->hotplug->ops;
|
||||||
unsigned long lattention;
|
unsigned long lattention;
|
||||||
u8 attention;
|
u8 attention;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
@ -169,7 +169,7 @@ static ssize_t attention_write_file(struct pci_slot *slot, const char *buf,
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
if (ops->set_attention_status)
|
if (ops->set_attention_status)
|
||||||
retval = ops->set_attention_status(slot->hotplug, attention);
|
retval = ops->set_attention_status(pci_slot->hotplug, attention);
|
||||||
module_put(ops->owner);
|
module_put(ops->owner);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
@ -184,12 +184,12 @@ static struct pci_slot_attribute hotplug_slot_attr_attention = {
|
||||||
.store = attention_write_file
|
.store = attention_write_file
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t latch_read_file(struct pci_slot *slot, char *buf)
|
static ssize_t latch_read_file(struct pci_slot *pci_slot, char *buf)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
u8 value;
|
u8 value;
|
||||||
|
|
||||||
retval = get_latch_status(slot->hotplug, &value);
|
retval = get_latch_status(pci_slot->hotplug, &value);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -201,12 +201,12 @@ static struct pci_slot_attribute hotplug_slot_attr_latch = {
|
||||||
.show = latch_read_file,
|
.show = latch_read_file,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t presence_read_file(struct pci_slot *slot, char *buf)
|
static ssize_t presence_read_file(struct pci_slot *pci_slot, char *buf)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
u8 value;
|
u8 value;
|
||||||
|
|
||||||
retval = get_adapter_status(slot->hotplug, &value);
|
retval = get_adapter_status(pci_slot->hotplug, &value);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -307,43 +307,43 @@ static bool has_test_file(struct pci_slot *pci_slot)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fs_add_slot(struct pci_slot *slot)
|
static int fs_add_slot(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
/* Create symbolic link to the hotplug driver module */
|
/* Create symbolic link to the hotplug driver module */
|
||||||
pci_hp_create_module_link(slot);
|
pci_hp_create_module_link(pci_slot);
|
||||||
|
|
||||||
if (has_power_file(slot)) {
|
if (has_power_file(pci_slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_power.attr);
|
&hotplug_slot_attr_power.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_power;
|
goto exit_power;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_attention_file(slot)) {
|
if (has_attention_file(pci_slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_attention.attr);
|
&hotplug_slot_attr_attention.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_attention;
|
goto exit_attention;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_latch_file(slot)) {
|
if (has_latch_file(pci_slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_latch.attr);
|
&hotplug_slot_attr_latch.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_latch;
|
goto exit_latch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_adapter_file(slot)) {
|
if (has_adapter_file(pci_slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_presence.attr);
|
&hotplug_slot_attr_presence.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_adapter;
|
goto exit_adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_test_file(slot)) {
|
if (has_test_file(pci_slot)) {
|
||||||
retval = sysfs_create_file(&slot->kobj,
|
retval = sysfs_create_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_test.attr);
|
&hotplug_slot_attr_test.attr);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto exit_test;
|
goto exit_test;
|
||||||
|
@ -352,45 +352,45 @@ static int fs_add_slot(struct pci_slot *slot)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
exit_test:
|
exit_test:
|
||||||
if (has_adapter_file(slot))
|
if (has_adapter_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj,
|
sysfs_remove_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_presence.attr);
|
&hotplug_slot_attr_presence.attr);
|
||||||
exit_adapter:
|
exit_adapter:
|
||||||
if (has_latch_file(slot))
|
if (has_latch_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
|
sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr);
|
||||||
exit_latch:
|
exit_latch:
|
||||||
if (has_attention_file(slot))
|
if (has_attention_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj,
|
sysfs_remove_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_attention.attr);
|
&hotplug_slot_attr_attention.attr);
|
||||||
exit_attention:
|
exit_attention:
|
||||||
if (has_power_file(slot))
|
if (has_power_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
|
sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr);
|
||||||
exit_power:
|
exit_power:
|
||||||
pci_hp_remove_module_link(slot);
|
pci_hp_remove_module_link(pci_slot);
|
||||||
exit:
|
exit:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fs_remove_slot(struct pci_slot *slot)
|
static void fs_remove_slot(struct pci_slot *pci_slot)
|
||||||
{
|
{
|
||||||
if (has_power_file(slot))
|
if (has_power_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
|
sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr);
|
||||||
|
|
||||||
if (has_attention_file(slot))
|
if (has_attention_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj,
|
sysfs_remove_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_attention.attr);
|
&hotplug_slot_attr_attention.attr);
|
||||||
|
|
||||||
if (has_latch_file(slot))
|
if (has_latch_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
|
sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr);
|
||||||
|
|
||||||
if (has_adapter_file(slot))
|
if (has_adapter_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj,
|
sysfs_remove_file(&pci_slot->kobj,
|
||||||
&hotplug_slot_attr_presence.attr);
|
&hotplug_slot_attr_presence.attr);
|
||||||
|
|
||||||
if (has_test_file(slot))
|
if (has_test_file(pci_slot))
|
||||||
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr);
|
sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_test.attr);
|
||||||
|
|
||||||
pci_hp_remove_module_link(slot);
|
pci_hp_remove_module_link(pci_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hotplug_slot *get_slot_from_name(const char *name)
|
static struct hotplug_slot *get_slot_from_name(const char *name)
|
||||||
|
@ -467,37 +467,37 @@ EXPORT_SYMBOL_GPL(__pci_hp_register);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
|
* pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
|
||||||
* @hotplug: pointer to the &struct hotplug_slot to deregister
|
* @slot: pointer to the &struct hotplug_slot to deregister
|
||||||
*
|
*
|
||||||
* The @slot must have been registered with the pci hotplug subsystem
|
* The @slot must have been registered with the pci hotplug subsystem
|
||||||
* previously with a call to pci_hp_register().
|
* previously with a call to pci_hp_register().
|
||||||
*
|
*
|
||||||
* Returns 0 if successful, anything else for an error.
|
* Returns 0 if successful, anything else for an error.
|
||||||
*/
|
*/
|
||||||
int pci_hp_deregister(struct hotplug_slot *hotplug)
|
int pci_hp_deregister(struct hotplug_slot *slot)
|
||||||
{
|
{
|
||||||
struct hotplug_slot *temp;
|
struct hotplug_slot *temp;
|
||||||
struct pci_slot *slot;
|
struct pci_slot *pci_slot;
|
||||||
|
|
||||||
if (!hotplug)
|
if (!slot)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
mutex_lock(&pci_hp_mutex);
|
mutex_lock(&pci_hp_mutex);
|
||||||
temp = get_slot_from_name(hotplug_slot_name(hotplug));
|
temp = get_slot_from_name(hotplug_slot_name(slot));
|
||||||
if (temp != hotplug) {
|
if (temp != slot) {
|
||||||
mutex_unlock(&pci_hp_mutex);
|
mutex_unlock(&pci_hp_mutex);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_del(&hotplug->slot_list);
|
list_del(&slot->slot_list);
|
||||||
|
|
||||||
slot = hotplug->pci_slot;
|
pci_slot = slot->pci_slot;
|
||||||
fs_remove_slot(slot);
|
fs_remove_slot(pci_slot);
|
||||||
dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug));
|
dbg("Removed slot %s from the list\n", hotplug_slot_name(slot));
|
||||||
|
|
||||||
hotplug->release(hotplug);
|
slot->release(slot);
|
||||||
slot->hotplug = NULL;
|
pci_slot->hotplug = NULL;
|
||||||
pci_destroy_slot(slot);
|
pci_destroy_slot(pci_slot);
|
||||||
mutex_unlock(&pci_hp_mutex);
|
mutex_unlock(&pci_hp_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -506,7 +506,7 @@ EXPORT_SYMBOL_GPL(pci_hp_deregister);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_hp_change_slot_info - changes the slot's information structure in the core
|
* pci_hp_change_slot_info - changes the slot's information structure in the core
|
||||||
* @hotplug: pointer to the slot whose info has changed
|
* @slot: pointer to the slot whose info has changed
|
||||||
* @info: pointer to the info copy into the slot's info structure
|
* @info: pointer to the info copy into the slot's info structure
|
||||||
*
|
*
|
||||||
* @slot must have been registered with the pci
|
* @slot must have been registered with the pci
|
||||||
|
@ -514,13 +514,13 @@ EXPORT_SYMBOL_GPL(pci_hp_deregister);
|
||||||
*
|
*
|
||||||
* Returns 0 if successful, anything else for an error.
|
* Returns 0 if successful, anything else for an error.
|
||||||
*/
|
*/
|
||||||
int pci_hp_change_slot_info(struct hotplug_slot *hotplug,
|
int pci_hp_change_slot_info(struct hotplug_slot *slot,
|
||||||
struct hotplug_slot_info *info)
|
struct hotplug_slot_info *info)
|
||||||
{
|
{
|
||||||
if (!hotplug || !info)
|
if (!slot || !info)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));
|
memcpy(slot->info, info, sizeof(struct hotplug_slot_info));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,18 +101,12 @@ struct controller {
|
||||||
unsigned int power_fault_detected;
|
unsigned int power_fault_detected;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INT_BUTTON_IGNORE 0
|
|
||||||
#define INT_PRESENCE_ON 1
|
#define INT_PRESENCE_ON 1
|
||||||
#define INT_PRESENCE_OFF 2
|
#define INT_PRESENCE_OFF 2
|
||||||
#define INT_SWITCH_CLOSE 3
|
#define INT_POWER_FAULT 3
|
||||||
#define INT_SWITCH_OPEN 4
|
#define INT_BUTTON_PRESS 4
|
||||||
#define INT_POWER_FAULT 5
|
#define INT_LINK_UP 5
|
||||||
#define INT_POWER_FAULT_CLEAR 6
|
#define INT_LINK_DOWN 6
|
||||||
#define INT_BUTTON_PRESS 7
|
|
||||||
#define INT_BUTTON_RELEASE 8
|
|
||||||
#define INT_BUTTON_CANCEL 9
|
|
||||||
#define INT_LINK_UP 10
|
|
||||||
#define INT_LINK_DOWN 11
|
|
||||||
|
|
||||||
#define STATIC_STATE 0
|
#define STATIC_STATE 0
|
||||||
#define BLINKINGON_STATE 1
|
#define BLINKINGON_STATE 1
|
||||||
|
|
|
@ -109,21 +109,23 @@ static int pcie_poll_cmd(struct controller *ctrl, int timeout)
|
||||||
struct pci_dev *pdev = ctrl_dev(ctrl);
|
struct pci_dev *pdev = ctrl_dev(ctrl);
|
||||||
u16 slot_status;
|
u16 slot_status;
|
||||||
|
|
||||||
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
|
while (true) {
|
||||||
if (slot_status & PCI_EXP_SLTSTA_CC) {
|
|
||||||
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
|
|
||||||
PCI_EXP_SLTSTA_CC);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
while (timeout > 0) {
|
|
||||||
msleep(10);
|
|
||||||
timeout -= 10;
|
|
||||||
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
|
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
|
||||||
|
if (slot_status == (u16) ~0) {
|
||||||
|
ctrl_info(ctrl, "%s: no response from device\n",
|
||||||
|
__func__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (slot_status & PCI_EXP_SLTSTA_CC) {
|
if (slot_status & PCI_EXP_SLTSTA_CC) {
|
||||||
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
|
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
|
||||||
PCI_EXP_SLTSTA_CC);
|
PCI_EXP_SLTSTA_CC);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (timeout < 0)
|
||||||
|
break;
|
||||||
|
msleep(10);
|
||||||
|
timeout -= 10;
|
||||||
}
|
}
|
||||||
return 0; /* timeout */
|
return 0; /* timeout */
|
||||||
}
|
}
|
||||||
|
@ -190,6 +192,11 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
|
||||||
pcie_wait_cmd(ctrl);
|
pcie_wait_cmd(ctrl);
|
||||||
|
|
||||||
pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
|
pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
|
||||||
|
if (slot_ctrl == (u16) ~0) {
|
||||||
|
ctrl_info(ctrl, "%s: no response from device\n", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
slot_ctrl &= ~mask;
|
slot_ctrl &= ~mask;
|
||||||
slot_ctrl |= (cmd & mask);
|
slot_ctrl |= (cmd & mask);
|
||||||
ctrl->cmd_busy = 1;
|
ctrl->cmd_busy = 1;
|
||||||
|
@ -205,6 +212,7 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
|
||||||
if (wait)
|
if (wait)
|
||||||
pcie_wait_cmd(ctrl);
|
pcie_wait_cmd(ctrl);
|
||||||
|
|
||||||
|
out:
|
||||||
mutex_unlock(&ctrl->ctrl_lock);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +543,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
struct slot *slot = ctrl->slot;
|
struct slot *slot = ctrl->slot;
|
||||||
u16 detected, intr_loc;
|
u16 detected, intr_loc;
|
||||||
u8 open, present;
|
u8 present;
|
||||||
bool link;
|
bool link;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -546,9 +554,14 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
||||||
intr_loc = 0;
|
intr_loc = 0;
|
||||||
do {
|
do {
|
||||||
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &detected);
|
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &detected);
|
||||||
|
if (detected == (u16) ~0) {
|
||||||
|
ctrl_info(ctrl, "%s: no response from device\n",
|
||||||
|
__func__);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
|
detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
|
||||||
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
|
PCI_EXP_SLTSTA_PDC |
|
||||||
PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
|
PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
|
||||||
detected &= ~intr_loc;
|
detected &= ~intr_loc;
|
||||||
intr_loc |= detected;
|
intr_loc |= detected;
|
||||||
|
@ -581,15 +594,6 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
||||||
if (!(intr_loc & ~PCI_EXP_SLTSTA_CC))
|
if (!(intr_loc & ~PCI_EXP_SLTSTA_CC))
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
||||||
/* Check MRL Sensor Changed */
|
|
||||||
if (intr_loc & PCI_EXP_SLTSTA_MRLSC) {
|
|
||||||
pciehp_get_latch_status(slot, &open);
|
|
||||||
ctrl_info(ctrl, "Latch %s on Slot(%s)\n",
|
|
||||||
open ? "open" : "close", slot_name(slot));
|
|
||||||
pciehp_queue_interrupt_event(slot, open ? INT_SWITCH_OPEN :
|
|
||||||
INT_SWITCH_CLOSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check Attention Button Pressed */
|
/* Check Attention Button Pressed */
|
||||||
if (intr_loc & PCI_EXP_SLTSTA_ABP) {
|
if (intr_loc & PCI_EXP_SLTSTA_ABP) {
|
||||||
ctrl_info(ctrl, "Button pressed on Slot(%s)\n",
|
ctrl_info(ctrl, "Button pressed on Slot(%s)\n",
|
||||||
|
@ -649,13 +653,11 @@ void pcie_enable_notification(struct controller *ctrl)
|
||||||
cmd |= PCI_EXP_SLTCTL_ABPE;
|
cmd |= PCI_EXP_SLTCTL_ABPE;
|
||||||
else
|
else
|
||||||
cmd |= PCI_EXP_SLTCTL_PDCE;
|
cmd |= PCI_EXP_SLTCTL_PDCE;
|
||||||
if (MRL_SENS(ctrl))
|
|
||||||
cmd |= PCI_EXP_SLTCTL_MRLSCE;
|
|
||||||
if (!pciehp_poll_mode)
|
if (!pciehp_poll_mode)
|
||||||
cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE;
|
cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE;
|
||||||
|
|
||||||
mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
|
mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
|
||||||
PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
|
PCI_EXP_SLTCTL_PFDE |
|
||||||
PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
|
PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
|
||||||
PCI_EXP_SLTCTL_DLLSCE);
|
PCI_EXP_SLTCTL_DLLSCE);
|
||||||
|
|
||||||
|
|
|
@ -1139,7 +1139,6 @@ int pci_setup_device(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
u32 class;
|
u32 class;
|
||||||
u8 hdr_type;
|
u8 hdr_type;
|
||||||
struct pci_slot *slot;
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
struct pci_bus_region region;
|
struct pci_bus_region region;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
@ -1155,10 +1154,7 @@ int pci_setup_device(struct pci_dev *dev)
|
||||||
dev->error_state = pci_channel_io_normal;
|
dev->error_state = pci_channel_io_normal;
|
||||||
set_pcie_port_type(dev);
|
set_pcie_port_type(dev);
|
||||||
|
|
||||||
list_for_each_entry(slot, &dev->bus->slots, list)
|
pci_dev_assign_slot(dev);
|
||||||
if (PCI_SLOT(dev->devfn) == slot->number)
|
|
||||||
dev->slot = slot;
|
|
||||||
|
|
||||||
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
|
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
|
||||||
set this higher, assuming the system even supports it. */
|
set this higher, assuming the system even supports it. */
|
||||||
dev->dma_mask = 0xffffffff;
|
dev->dma_mask = 0xffffffff;
|
||||||
|
@ -1546,6 +1542,9 @@ static void pci_init_capabilities(struct pci_dev *dev)
|
||||||
/* Single Root I/O Virtualization */
|
/* Single Root I/O Virtualization */
|
||||||
pci_iov_init(dev);
|
pci_iov_init(dev);
|
||||||
|
|
||||||
|
/* Address Translation Services */
|
||||||
|
pci_ats_init(dev);
|
||||||
|
|
||||||
/* Enable ACS P2P upstream forwarding */
|
/* Enable ACS P2P upstream forwarding */
|
||||||
pci_enable_acs(dev);
|
pci_enable_acs(dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3872,6 +3872,9 @@ static const struct pci_dev_acs_enabled {
|
||||||
{ PCI_VENDOR_ID_INTEL, 0x105F, pci_quirk_mf_endpoint_acs },
|
{ PCI_VENDOR_ID_INTEL, 0x105F, pci_quirk_mf_endpoint_acs },
|
||||||
{ PCI_VENDOR_ID_INTEL, 0x1060, pci_quirk_mf_endpoint_acs },
|
{ PCI_VENDOR_ID_INTEL, 0x1060, pci_quirk_mf_endpoint_acs },
|
||||||
{ PCI_VENDOR_ID_INTEL, 0x10D9, pci_quirk_mf_endpoint_acs },
|
{ PCI_VENDOR_ID_INTEL, 0x10D9, pci_quirk_mf_endpoint_acs },
|
||||||
|
/* I219 */
|
||||||
|
{ PCI_VENDOR_ID_INTEL, 0x15b7, pci_quirk_mf_endpoint_acs },
|
||||||
|
{ PCI_VENDOR_ID_INTEL, 0x15b8, pci_quirk_mf_endpoint_acs },
|
||||||
/* Intel PCH root ports */
|
/* Intel PCH root ports */
|
||||||
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
|
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
|
||||||
{ 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */
|
{ 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
struct kset *pci_slots_kset;
|
struct kset *pci_slots_kset;
|
||||||
EXPORT_SYMBOL_GPL(pci_slots_kset);
|
EXPORT_SYMBOL_GPL(pci_slots_kset);
|
||||||
|
static DEFINE_MUTEX(pci_slot_mutex);
|
||||||
|
|
||||||
static ssize_t pci_slot_attr_show(struct kobject *kobj,
|
static ssize_t pci_slot_attr_show(struct kobject *kobj,
|
||||||
struct attribute *attr, char *buf)
|
struct attribute *attr, char *buf)
|
||||||
|
@ -106,9 +107,11 @@ static void pci_slot_release(struct kobject *kobj)
|
||||||
dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n",
|
dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n",
|
||||||
slot->number, pci_slot_name(slot));
|
slot->number, pci_slot_name(slot));
|
||||||
|
|
||||||
|
down_read(&pci_bus_sem);
|
||||||
list_for_each_entry(dev, &slot->bus->devices, bus_list)
|
list_for_each_entry(dev, &slot->bus->devices, bus_list)
|
||||||
if (PCI_SLOT(dev->devfn) == slot->number)
|
if (PCI_SLOT(dev->devfn) == slot->number)
|
||||||
dev->slot = NULL;
|
dev->slot = NULL;
|
||||||
|
up_read(&pci_bus_sem);
|
||||||
|
|
||||||
list_del(&slot->list);
|
list_del(&slot->list);
|
||||||
|
|
||||||
|
@ -191,12 +194,22 @@ static int rename_slot(struct pci_slot *slot, const char *name)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pci_dev_assign_slot(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct pci_slot *slot;
|
||||||
|
|
||||||
|
mutex_lock(&pci_slot_mutex);
|
||||||
|
list_for_each_entry(slot, &dev->bus->slots, list)
|
||||||
|
if (PCI_SLOT(dev->devfn) == slot->number)
|
||||||
|
dev->slot = slot;
|
||||||
|
mutex_unlock(&pci_slot_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
|
static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
|
||||||
{
|
{
|
||||||
struct pci_slot *slot;
|
struct pci_slot *slot;
|
||||||
/*
|
|
||||||
* We already hold pci_bus_sem so don't worry
|
/* We already hold pci_slot_mutex */
|
||||||
*/
|
|
||||||
list_for_each_entry(slot, &parent->slots, list)
|
list_for_each_entry(slot, &parent->slots, list)
|
||||||
if (slot->number == slot_nr) {
|
if (slot->number == slot_nr) {
|
||||||
kobject_get(&slot->kobj);
|
kobject_get(&slot->kobj);
|
||||||
|
@ -253,7 +266,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
|
||||||
int err = 0;
|
int err = 0;
|
||||||
char *slot_name = NULL;
|
char *slot_name = NULL;
|
||||||
|
|
||||||
down_write(&pci_bus_sem);
|
mutex_lock(&pci_slot_mutex);
|
||||||
|
|
||||||
if (slot_nr == -1)
|
if (slot_nr == -1)
|
||||||
goto placeholder;
|
goto placeholder;
|
||||||
|
@ -301,16 +314,18 @@ placeholder:
|
||||||
INIT_LIST_HEAD(&slot->list);
|
INIT_LIST_HEAD(&slot->list);
|
||||||
list_add(&slot->list, &parent->slots);
|
list_add(&slot->list, &parent->slots);
|
||||||
|
|
||||||
|
down_read(&pci_bus_sem);
|
||||||
list_for_each_entry(dev, &parent->devices, bus_list)
|
list_for_each_entry(dev, &parent->devices, bus_list)
|
||||||
if (PCI_SLOT(dev->devfn) == slot_nr)
|
if (PCI_SLOT(dev->devfn) == slot_nr)
|
||||||
dev->slot = slot;
|
dev->slot = slot;
|
||||||
|
up_read(&pci_bus_sem);
|
||||||
|
|
||||||
dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n",
|
dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n",
|
||||||
slot_nr, pci_slot_name(slot));
|
slot_nr, pci_slot_name(slot));
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(slot_name);
|
kfree(slot_name);
|
||||||
up_write(&pci_bus_sem);
|
mutex_unlock(&pci_slot_mutex);
|
||||||
return slot;
|
return slot;
|
||||||
err:
|
err:
|
||||||
kfree(slot);
|
kfree(slot);
|
||||||
|
@ -332,9 +347,9 @@ void pci_destroy_slot(struct pci_slot *slot)
|
||||||
dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n",
|
dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n",
|
||||||
slot->number, atomic_read(&slot->kobj.kref.refcount) - 1);
|
slot->number, atomic_read(&slot->kobj.kref.refcount) - 1);
|
||||||
|
|
||||||
down_write(&pci_bus_sem);
|
mutex_lock(&pci_slot_mutex);
|
||||||
kobject_put(&slot->kobj);
|
kobject_put(&slot->kobj);
|
||||||
up_write(&pci_bus_sem);
|
mutex_unlock(&pci_slot_mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_destroy_slot);
|
EXPORT_SYMBOL_GPL(pci_destroy_slot);
|
||||||
|
|
||||||
|
|
|
@ -3,55 +3,6 @@
|
||||||
|
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
/* Address Translation Service */
|
|
||||||
struct pci_ats {
|
|
||||||
int pos; /* capability position */
|
|
||||||
int stu; /* Smallest Translation Unit */
|
|
||||||
int qdep; /* Invalidate Queue Depth */
|
|
||||||
int ref_cnt; /* Physical Function reference count */
|
|
||||||
unsigned int is_enabled:1; /* Enable bit is set */
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_ATS
|
|
||||||
|
|
||||||
int pci_enable_ats(struct pci_dev *dev, int ps);
|
|
||||||
void pci_disable_ats(struct pci_dev *dev);
|
|
||||||
int pci_ats_queue_depth(struct pci_dev *dev);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pci_ats_enabled - query the ATS status
|
|
||||||
* @dev: the PCI device
|
|
||||||
*
|
|
||||||
* Returns 1 if ATS capability is enabled, or 0 if not.
|
|
||||||
*/
|
|
||||||
static inline int pci_ats_enabled(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->ats && dev->ats->is_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* CONFIG_PCI_ATS */
|
|
||||||
|
|
||||||
static inline int pci_enable_ats(struct pci_dev *dev, int ps)
|
|
||||||
{
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void pci_disable_ats(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int pci_ats_queue_depth(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int pci_ats_enabled(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CONFIG_PCI_ATS */
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_PRI
|
#ifdef CONFIG_PCI_PRI
|
||||||
|
|
||||||
int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
|
int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
|
||||||
|
|
|
@ -345,6 +345,7 @@ struct pci_dev {
|
||||||
unsigned int msi_enabled:1;
|
unsigned int msi_enabled:1;
|
||||||
unsigned int msix_enabled:1;
|
unsigned int msix_enabled:1;
|
||||||
unsigned int ari_enabled:1; /* ARI forwarding */
|
unsigned int ari_enabled:1; /* ARI forwarding */
|
||||||
|
unsigned int ats_enabled:1; /* Address Translation Service */
|
||||||
unsigned int is_managed:1;
|
unsigned int is_managed:1;
|
||||||
unsigned int needs_freset:1; /* Dev requires fundamental reset */
|
unsigned int needs_freset:1; /* Dev requires fundamental reset */
|
||||||
unsigned int state_saved:1;
|
unsigned int state_saved:1;
|
||||||
|
@ -377,7 +378,9 @@ struct pci_dev {
|
||||||
struct pci_sriov *sriov; /* SR-IOV capability related */
|
struct pci_sriov *sriov; /* SR-IOV capability related */
|
||||||
struct pci_dev *physfn; /* the PF this VF is associated with */
|
struct pci_dev *physfn; /* the PF this VF is associated with */
|
||||||
};
|
};
|
||||||
struct pci_ats *ats; /* Address Translation Service */
|
u16 ats_cap; /* ATS Capability offset */
|
||||||
|
u8 ats_stu; /* ATS Smallest Translation Unit */
|
||||||
|
atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */
|
||||||
#endif
|
#endif
|
||||||
phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
|
phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
|
||||||
size_t romlen; /* Length of ROM if it's not from the BAR */
|
size_t romlen; /* Length of ROM if it's not from the BAR */
|
||||||
|
@ -448,7 +451,8 @@ struct pci_bus {
|
||||||
struct list_head children; /* list of child buses */
|
struct list_head children; /* list of child buses */
|
||||||
struct list_head devices; /* list of devices on this bus */
|
struct list_head devices; /* list of devices on this bus */
|
||||||
struct pci_dev *self; /* bridge device as seen by parent */
|
struct pci_dev *self; /* bridge device as seen by parent */
|
||||||
struct list_head slots; /* list of slots on this bus */
|
struct list_head slots; /* list of slots on this bus;
|
||||||
|
protected by pci_slot_mutex */
|
||||||
struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
|
struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
|
||||||
struct list_head resources; /* address space routed to this bus */
|
struct list_head resources; /* address space routed to this bus */
|
||||||
struct resource busn_res; /* bus numbers routed to this bus */
|
struct resource busn_res; /* bus numbers routed to this bus */
|
||||||
|
@ -799,6 +803,11 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
|
||||||
const char *name,
|
const char *name,
|
||||||
struct hotplug_slot *hotplug);
|
struct hotplug_slot *hotplug);
|
||||||
void pci_destroy_slot(struct pci_slot *slot);
|
void pci_destroy_slot(struct pci_slot *slot);
|
||||||
|
#ifdef CONFIG_SYSFS
|
||||||
|
void pci_dev_assign_slot(struct pci_dev *dev);
|
||||||
|
#else
|
||||||
|
static inline void pci_dev_assign_slot(struct pci_dev *dev) { }
|
||||||
|
#endif
|
||||||
int pci_scan_slot(struct pci_bus *bus, int devfn);
|
int pci_scan_slot(struct pci_bus *bus, int devfn);
|
||||||
struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn);
|
struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn);
|
||||||
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
|
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
|
||||||
|
@ -1313,6 +1322,19 @@ int ht_create_irq(struct pci_dev *dev, int idx);
|
||||||
void ht_destroy_irq(unsigned int irq);
|
void ht_destroy_irq(unsigned int irq);
|
||||||
#endif /* CONFIG_HT_IRQ */
|
#endif /* CONFIG_HT_IRQ */
|
||||||
|
|
||||||
|
#ifdef CONFIG_PCI_ATS
|
||||||
|
/* Address Translation Service */
|
||||||
|
void pci_ats_init(struct pci_dev *dev);
|
||||||
|
int pci_enable_ats(struct pci_dev *dev, int ps);
|
||||||
|
void pci_disable_ats(struct pci_dev *dev);
|
||||||
|
int pci_ats_queue_depth(struct pci_dev *dev);
|
||||||
|
#else
|
||||||
|
static inline void pci_ats_init(struct pci_dev *d) { }
|
||||||
|
static inline int pci_enable_ats(struct pci_dev *d, int ps) { return -ENODEV; }
|
||||||
|
static inline void pci_disable_ats(struct pci_dev *d) { }
|
||||||
|
static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; }
|
||||||
|
#endif
|
||||||
|
|
||||||
void pci_cfg_access_lock(struct pci_dev *dev);
|
void pci_cfg_access_lock(struct pci_dev *dev);
|
||||||
bool pci_cfg_access_trylock(struct pci_dev *dev);
|
bool pci_cfg_access_trylock(struct pci_dev *dev);
|
||||||
void pci_cfg_access_unlock(struct pci_dev *dev);
|
void pci_cfg_access_unlock(struct pci_dev *dev);
|
||||||
|
|
Loading…
Reference in New Issue