lkml.org 
[lkml]   [2020]   [Nov]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    SubjectRe: [EXTERNAL] [tip: x86/apic] x86/io_apic: Cleanup trigger/polarity helpers
    From
    Date
    On Wed, 2020-11-11 at 10:46 +0100, Thomas Gleixner wrote:
    > Looking at it now with brain awake, the XTSUP stuff is pretty much
    > the same as DMAR, which I didn't realize yesterday. The affinity
    > notifier muck is not needed when we have a write_msg() function which
    > twiddles the bits into those other locations.

    I kind of hate the fact that it's swizzling those bits through invalid
    MSI messages, so I did it as its own irqdomain using
    irq_domain_create_hierarchy() directly instead of
    msi_create_irq_domain().

    Looks something like this, although I believe I'm missing a call to
    irq_domain_set_info() somewhere which means that the irq_chip
    'intcapxt_controller' isn't being used at all...


    diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
    index 90a8add186e0..b68fe10aa67d 100644
    --- a/drivers/iommu/amd/init.c
    +++ b/drivers/iommu/amd/init.c
    @@ -16,6 +16,7 @@
    #include <linux/syscore_ops.h>
    #include <linux/interrupt.h>
    #include <linux/msi.h>
    +#include <linux/irq.h>
    #include <linux/amd-iommu.h>
    #include <linux/export.h>
    #include <linux/kmemleak.h>
    @@ -1563,8 +1564,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
    * for MSI address lo/hi/data, we need to check both
    * EFR[XtSup] and EFR[MsiCapMmioSup] for x2APIC support.
    */
    - if ((h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT)) &&
    - (h->efr_reg & BIT(IOMMU_EFR_MSICAPMMIOSUP_SHIFT)))
    + if (h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT))
    amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE;
    break;
    default:
    @@ -1978,28 +1978,27 @@ union intcapxt {
    destid_24_31 : 8;
    } __attribute__ ((packed));

    -/*
    - * Setup the IntCapXT registers with interrupt routing information
    - * based on the PCI MSI capability block registers, accessed via
    - * MMIO MSI address low/hi and MSI data registers.
    - */
    -static void iommu_update_intcapxt(struct amd_iommu *iommu)
    +/* We weren't actually doing anything before. Should we? */
    +static void intcapxt_unmask_irq(struct irq_data *data)
    {
    - struct msi_msg msg;
    - union intcapxt xt;
    - u32 destid;
    +}
    +static void intcapxt_mask_irq(struct irq_data *data)
    +{
    +}

    - msg.address_lo = readl(iommu->mmio_base + MMIO_MSI_ADDR_LO_OFFSET);
    - msg.address_hi = readl(iommu->mmio_base + MMIO_MSI_ADDR_HI_OFFSET);
    - msg.data = readl(iommu->mmio_base + MMIO_MSI_DATA_OFFSET);

    - destid = x86_msi_msg_get_destid(&msg, x2apic_enabled());
    +static int intcapxt_irqdomain_activate(struct irq_domain *domain,
    + struct irq_data *irqd, bool reserve)
    +{
    + struct amd_iommu *iommu = domain->host_data;
    + struct irq_cfg *cfg = irqd_cfg(irqd);
    + union intcapxt xt;

    xt.capxt = 0ULL;
    - xt.dest_mode_logical = msg.arch_data.dest_mode_logical;
    - xt.vector = msg.arch_data.vector;
    - xt.destid_0_23 = destid & GENMASK(23, 0);
    - xt.destid_24_31 = destid >> 24;
    + xt.dest_mode_logical = apic->dest_mode_logical;
    + xt.vector = cfg->vector;
    + xt.destid_0_23 = cfg->dest_apicid & GENMASK(23, 0);
    + xt.destid_24_31 = cfg->dest_apicid >> 24;

    /**
    * Current IOMMU implemtation uses the same IRQ for all
    @@ -2008,64 +2007,117 @@ static void iommu_update_intcapxt(struct amd_iommu *iommu)
    writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET);
    writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET);
    writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET);
    +
    + return 0;
    }

    -static void _irq_notifier_notify(struct irq_affinity_notify *notify,
    - const cpumask_t *mask)
    +static void intcapxt_irqdomain_deactivate(struct irq_domain *domain,
    + struct irq_data *irqd)
    {
    - struct amd_iommu *iommu;
    + intcapxt_mask_irq(irqd);
    +}

    - for_each_iommu(iommu) {
    - if (iommu->dev->irq == notify->irq) {
    - iommu_update_intcapxt(iommu);
    - break;
    - }
    - }
    +
    +static int intcapxt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
    + unsigned int nr_irqs, void *arg)
    +{
    + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
    }

    -static void _irq_notifier_release(struct kref *ref)
    +static void intcapxt_irqdomain_free(struct irq_domain *domain, unsigned int virq,
    + unsigned int nr_irqs)
    {
    + irq_domain_free_irqs_top(domain, virq, nr_irqs);
    }

    -static int iommu_init_intcapxt(struct amd_iommu *iommu)
    +static int intcapxt_set_affinity(struct irq_data *irqd,
    + const struct cpumask *mask, bool force)
    {
    + struct irq_data *parent = irqd->parent_data;
    int ret;
    - struct irq_affinity_notify *notify = &iommu->intcapxt_notify;

    - /**
    - * IntCapXT requires XTSup=1 and MsiCapMmioSup=1,
    - * which can be inferred from amd_iommu_xt_mode.
    - */
    - if (amd_iommu_xt_mode != IRQ_REMAP_X2APIC_MODE)
    - return 0;
    + ret = parent->chip->irq_set_affinity(parent, mask, force);
    + if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
    + return ret;

    - /**
    - * Also, we need to setup notifier to update the IntCapXT registers
    - * whenever the irq affinity is changed from user-space.
    - */
    - notify->irq = iommu->dev->irq;
    - notify->notify = _irq_notifier_notify,
    - notify->release = _irq_notifier_release,
    - ret = irq_set_affinity_notifier(iommu->dev->irq, notify);
    + return intcapxt_irqdomain_activate(irqd->domain, irqd, false);
    +}
    +
    +static struct irq_chip intcapxt_controller = {
    + .name = "IOMMU-MSI",
    + .irq_unmask = intcapxt_unmask_irq,
    + .irq_mask = intcapxt_mask_irq,
    + .irq_ack = irq_chip_ack_parent,
    + .irq_retrigger = irq_chip_retrigger_hierarchy,
    + .irq_set_affinity = intcapxt_set_affinity,
    + .flags = IRQCHIP_SKIP_SET_WAKE,
    +};
    +
    +static const struct irq_domain_ops intcapxt_domain_ops = {
    + .alloc = intcapxt_irqdomain_alloc,
    + .free = intcapxt_irqdomain_free,
    + .activate = intcapxt_irqdomain_activate,
    + .deactivate = intcapxt_irqdomain_deactivate,
    +};
    +
    +static struct irq_domain *iommu_get_irqdomain(struct amd_iommu *iommu)
    +{
    + struct irq_domain *domain = NULL;
    + struct fwnode_handle *fn;
    +
    + fn = irq_domain_alloc_named_id_fwnode("AMD-Vi-MSI", iommu->index);
    + if (!fn)
    + return NULL;
    +
    + domain = irq_domain_create_hierarchy(x86_vector_domain, 0, 0,
    + fn, &intcapxt_domain_ops,
    + iommu);
    + if (!domain)
    + irq_domain_free_fwnode(fn);
    +
    + return domain;
    +}
    +
    +static int iommu_setup_intcapxt(struct amd_iommu *iommu)
    +{
    + struct irq_domain *domain;
    + int irq, ret;
    +
    + domain = iommu_get_irqdomain(iommu);
    + if (!domain)
    + return -ENXIO;
    +
    + irq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, NULL);
    + if (irq < 0) {
    + irq_domain_remove(domain);
    + return irq;
    + }
    +
    + ret = request_threaded_irq(irq,
    + amd_iommu_int_handler,
    + amd_iommu_int_thread,
    + 0, "AMD-Vi",
    + iommu);
    if (ret) {
    - pr_err("Failed to register irq affinity notifier (devid=%#x, irq %d)\n",
    - iommu->devid, iommu->dev->irq);
    + irq_domain_free_irqs(irq, 1);
    + irq_domain_remove(domain);
    return ret;
    }

    - iommu_update_intcapxt(iommu);
    iommu_feature_enable(iommu, CONTROL_INTCAPXT_EN);
    - return ret;
    + return 0;
    }

    -static int iommu_init_msi(struct amd_iommu *iommu)
    +static int iommu_init_irq(struct amd_iommu *iommu)
    {
    int ret;

    if (iommu->int_enabled)
    goto enable_faults;

    - if (iommu->dev->msi_cap)
    + if (amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE)
    + ret = iommu_setup_intcapxt(iommu);
    + else if (iommu->dev->msi_cap)
    ret = iommu_setup_msi(iommu);
    else
    ret = -ENODEV;
    @@ -2074,10 +2126,6 @@ static int iommu_init_msi(struct amd_iommu *iommu)
    return ret;

    enable_faults:
    - ret = iommu_init_intcapxt(iommu);
    - if (ret)
    - return ret;
    -
    iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);

    if (iommu->ppr_log != NULL)
    @@ -2700,7 +2748,7 @@ static int amd_iommu_enable_interrupts(void)
    int ret = 0;

    for_each_iommu(iommu) {
    - ret = iommu_init_msi(iommu);
    + ret = iommu_init_irq(iommu);
    if (ret)
    goto out;
    }[unhandled content-type:application/x-pkcs7-signature]
    \
     
     \ /
      Last update: 2020-11-11 11:37    [W:4.128 / U:0.368 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site