iommu/arm-smmu: Account for PMU interrupts
In preparation for SMMUv2 PMU support, rejig our IRQ setup code to account for PMU interrupts as additional resources. We can simplify the whole flow by only storing the context IRQs, since the global IRQs are devres-managed and we never refer to them beyond the initial request. CC: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> Signed-off-by: Robin Murphy <robin.murphy@arm.com> Link: https://lore.kernel.org/r/b2a40caaf1622eb35c555074a0d72f4f0513cff9.1645106346.git.robin.murphy@arm.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
8ddf4eff71
commit
97dfad194c
@@ -807,7 +807,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||||||
* Request context fault interrupt. Do this last to avoid the
|
* Request context fault interrupt. Do this last to avoid the
|
||||||
* handler seeing a half-initialised domain state.
|
* handler seeing a half-initialised domain state.
|
||||||
*/
|
*/
|
||||||
irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
|
irq = smmu->irqs[cfg->irptndx];
|
||||||
|
|
||||||
if (smmu->impl && smmu->impl->context_fault)
|
if (smmu->impl && smmu->impl->context_fault)
|
||||||
context_fault = smmu->impl->context_fault;
|
context_fault = smmu->impl->context_fault;
|
||||||
@@ -858,7 +858,7 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
|
|||||||
arm_smmu_write_context_bank(smmu, cfg->cbndx);
|
arm_smmu_write_context_bank(smmu, cfg->cbndx);
|
||||||
|
|
||||||
if (cfg->irptndx != ARM_SMMU_INVALID_IRPTNDX) {
|
if (cfg->irptndx != ARM_SMMU_INVALID_IRPTNDX) {
|
||||||
irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
|
irq = smmu->irqs[cfg->irptndx];
|
||||||
devm_free_irq(smmu->dev, irq, domain);
|
devm_free_irq(smmu->dev, irq, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1951,8 +1951,8 @@ static int acpi_smmu_get_data(u32 model, struct arm_smmu_device *smmu)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
|
static int arm_smmu_device_acpi_probe(struct arm_smmu_device *smmu,
|
||||||
struct arm_smmu_device *smmu)
|
u32 *global_irqs, u32 *pmu_irqs)
|
||||||
{
|
{
|
||||||
struct device *dev = smmu->dev;
|
struct device *dev = smmu->dev;
|
||||||
struct acpi_iort_node *node =
|
struct acpi_iort_node *node =
|
||||||
@@ -1968,7 +1968,8 @@ static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Ignore the configuration access interrupt */
|
/* Ignore the configuration access interrupt */
|
||||||
smmu->num_global_irqs = 1;
|
*global_irqs = 1;
|
||||||
|
*pmu_irqs = 0;
|
||||||
|
|
||||||
if (iort_smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK)
|
if (iort_smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK)
|
||||||
smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
|
smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
|
||||||
@@ -1976,25 +1977,24 @@ static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
|
static inline int arm_smmu_device_acpi_probe(struct arm_smmu_device *smmu,
|
||||||
struct arm_smmu_device *smmu)
|
u32 *global_irqs, u32 *pmu_irqs)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int arm_smmu_device_dt_probe(struct platform_device *pdev,
|
static int arm_smmu_device_dt_probe(struct arm_smmu_device *smmu,
|
||||||
struct arm_smmu_device *smmu)
|
u32 *global_irqs, u32 *pmu_irqs)
|
||||||
{
|
{
|
||||||
const struct arm_smmu_match_data *data;
|
const struct arm_smmu_match_data *data;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = smmu->dev;
|
||||||
bool legacy_binding;
|
bool legacy_binding;
|
||||||
|
|
||||||
if (of_property_read_u32(dev->of_node, "#global-interrupts",
|
if (of_property_read_u32(dev->of_node, "#global-interrupts", global_irqs))
|
||||||
&smmu->num_global_irqs)) {
|
return dev_err_probe(dev, -ENODEV,
|
||||||
dev_err(dev, "missing #global-interrupts property\n");
|
"missing #global-interrupts property\n");
|
||||||
return -ENODEV;
|
*pmu_irqs = 0;
|
||||||
}
|
|
||||||
|
|
||||||
data = of_device_get_match_data(dev);
|
data = of_device_get_match_data(dev);
|
||||||
smmu->version = data->version;
|
smmu->version = data->version;
|
||||||
@@ -2073,6 +2073,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||||||
struct arm_smmu_device *smmu;
|
struct arm_smmu_device *smmu;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
int num_irqs, i, err;
|
int num_irqs, i, err;
|
||||||
|
u32 global_irqs, pmu_irqs;
|
||||||
irqreturn_t (*global_fault)(int irq, void *dev);
|
irqreturn_t (*global_fault)(int irq, void *dev);
|
||||||
|
|
||||||
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
|
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
|
||||||
@@ -2083,10 +2084,9 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||||||
smmu->dev = dev;
|
smmu->dev = dev;
|
||||||
|
|
||||||
if (dev->of_node)
|
if (dev->of_node)
|
||||||
err = arm_smmu_device_dt_probe(pdev, smmu);
|
err = arm_smmu_device_dt_probe(smmu, &global_irqs, &pmu_irqs);
|
||||||
else
|
else
|
||||||
err = arm_smmu_device_acpi_probe(pdev, smmu);
|
err = arm_smmu_device_acpi_probe(smmu, &global_irqs, &pmu_irqs);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -2105,31 +2105,25 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(smmu))
|
if (IS_ERR(smmu))
|
||||||
return PTR_ERR(smmu);
|
return PTR_ERR(smmu);
|
||||||
|
|
||||||
num_irqs = 0;
|
num_irqs = platform_irq_count(pdev);
|
||||||
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
|
|
||||||
num_irqs++;
|
|
||||||
if (num_irqs > smmu->num_global_irqs)
|
|
||||||
smmu->num_context_irqs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!smmu->num_context_irqs) {
|
smmu->num_context_irqs = num_irqs - global_irqs - pmu_irqs;
|
||||||
dev_err(dev, "found %d interrupts but expected at least %d\n",
|
if (smmu->num_context_irqs <= 0)
|
||||||
num_irqs, smmu->num_global_irqs + 1);
|
return dev_err_probe(dev, -ENODEV,
|
||||||
return -ENODEV;
|
"found %d interrupts but expected at least %d\n",
|
||||||
}
|
num_irqs, global_irqs + pmu_irqs + 1);
|
||||||
|
|
||||||
smmu->irqs = devm_kcalloc(dev, num_irqs, sizeof(*smmu->irqs),
|
smmu->irqs = devm_kcalloc(dev, smmu->num_context_irqs,
|
||||||
GFP_KERNEL);
|
sizeof(*smmu->irqs), GFP_KERNEL);
|
||||||
if (!smmu->irqs) {
|
if (!smmu->irqs)
|
||||||
dev_err(dev, "failed to allocate %d irqs\n", num_irqs);
|
return dev_err_probe(dev, -ENOMEM, "failed to allocate %d irqs\n",
|
||||||
return -ENOMEM;
|
smmu->num_context_irqs);
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < num_irqs; ++i) {
|
for (i = 0; i < smmu->num_context_irqs; i++) {
|
||||||
int irq = platform_get_irq(pdev, i);
|
int irq = platform_get_irq(pdev, global_irqs + pmu_irqs + i);
|
||||||
|
|
||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
return -ENODEV;
|
return irq;
|
||||||
smmu->irqs[i] = irq;
|
smmu->irqs[i] = irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2165,17 +2159,18 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||||||
else
|
else
|
||||||
global_fault = arm_smmu_global_fault;
|
global_fault = arm_smmu_global_fault;
|
||||||
|
|
||||||
for (i = 0; i < smmu->num_global_irqs; ++i) {
|
for (i = 0; i < global_irqs; i++) {
|
||||||
err = devm_request_irq(smmu->dev, smmu->irqs[i],
|
int irq = platform_get_irq(pdev, i);
|
||||||
global_fault,
|
|
||||||
IRQF_SHARED,
|
if (irq < 0)
|
||||||
"arm-smmu global fault",
|
return irq;
|
||||||
smmu);
|
|
||||||
if (err) {
|
err = devm_request_irq(dev, irq, global_fault, IRQF_SHARED,
|
||||||
dev_err(dev, "failed to request global IRQ %d (%u)\n",
|
"arm-smmu global fault", smmu);
|
||||||
i, smmu->irqs[i]);
|
if (err)
|
||||||
return err;
|
return dev_err_probe(dev, err,
|
||||||
}
|
"failed to request global IRQ %d (%u)\n",
|
||||||
|
i, irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iommu_device_sysfs_add(&smmu->iommu, smmu->dev, NULL,
|
err = iommu_device_sysfs_add(&smmu->iommu, smmu->dev, NULL,
|
||||||
|
|||||||
@@ -318,11 +318,10 @@ struct arm_smmu_device {
|
|||||||
unsigned long pa_size;
|
unsigned long pa_size;
|
||||||
unsigned long pgsize_bitmap;
|
unsigned long pgsize_bitmap;
|
||||||
|
|
||||||
u32 num_global_irqs;
|
int num_context_irqs;
|
||||||
u32 num_context_irqs;
|
int num_clks;
|
||||||
unsigned int *irqs;
|
unsigned int *irqs;
|
||||||
struct clk_bulk_data *clks;
|
struct clk_bulk_data *clks;
|
||||||
int num_clks;
|
|
||||||
|
|
||||||
spinlock_t global_sync_lock;
|
spinlock_t global_sync_lock;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user