lkml.org 
[lkml]   [2018]   [May]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[tip:irq/core] genirq/msi: Allow level-triggered MSIs to be exposed by MSI providers
    Commit-ID:  0be8153cbc2af9a96e9ab8631fc3ba23bb52dbe3
    Gitweb: https://git.kernel.org/tip/0be8153cbc2af9a96e9ab8631fc3ba23bb52dbe3
    Author: Marc Zyngier <marc.zyngier@arm.com>
    AuthorDate: Tue, 8 May 2018 13:14:30 +0100
    Committer: Thomas Gleixner <tglx@linutronix.de>
    CommitDate: Sun, 13 May 2018 15:58:59 +0200

    genirq/msi: Allow level-triggered MSIs to be exposed by MSI providers

    So far, MSIs have been used to signal edge-triggered interrupts, as
    a write is a good model for an edge (you can't "unwrite" something).
    On the other hand, routing zillions of wires in an SoC because you
    need level interrupts is a bit extreme.

    People have come up with a variety of schemes to support this, which
    involves sending two messages: one to signal the interrupt, and one
    to clear it. Since the kernel cannot represent this, we've ended up
    with side-band mechanisms that are pretty awful.

    Instead, let's acknoledge the requirement, and ensure that, under the
    right circumstances, the irq_compose_msg and irq_write_msg can take
    as a parameter an array of two messages instead of a pointer to a
    single one. We also add some checking that the compose method only
    clobbers the second message if the MSI domain has been created with
    the MSI_FLAG_LEVEL_CAPABLE flags.

    Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Cc: Rob Herring <robh@kernel.org>
    Cc: Jason Cooper <jason@lakedaemon.net>
    Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
    Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
    Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
    Cc: Miquel Raynal <miquel.raynal@bootlin.com>
    Link: https://lkml.kernel.org/r/20180508121438.11301-2-marc.zyngier@arm.com

    ---
    include/linux/msi.h | 2 ++
    kernel/irq/msi.c | 33 ++++++++++++++++++++++++---------
    2 files changed, 26 insertions(+), 9 deletions(-)

    diff --git a/include/linux/msi.h b/include/linux/msi.h
    index 1f1bbb5b4679..5839d8062dfc 100644
    --- a/include/linux/msi.h
    +++ b/include/linux/msi.h
    @@ -289,6 +289,8 @@ enum {
    * MSI_FLAG_ACTIVATE_EARLY has been set.
    */
    MSI_FLAG_MUST_REACTIVATE = (1 << 5),
    + /* Is level-triggered capable, using two messages */
    + MSI_FLAG_LEVEL_CAPABLE = (1 << 6),
    };

    int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
    diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
    index 2a8571f72b17..4ca2fd46645d 100644
    --- a/kernel/irq/msi.c
    +++ b/kernel/irq/msi.c
    @@ -76,6 +76,19 @@ static inline void irq_chip_write_msi_msg(struct irq_data *data,
    data->chip->irq_write_msi_msg(data, msg);
    }

    +static void msi_check_level(struct irq_domain *domain, struct msi_msg *msg)
    +{
    + struct msi_domain_info *info = domain->host_data;
    +
    + /*
    + * If the MSI provider has messed with the second message and
    + * not advertized that it is level-capable, signal the breakage.
    + */
    + WARN_ON(!((info->flags & MSI_FLAG_LEVEL_CAPABLE) &&
    + (info->chip->flags & IRQCHIP_SUPPORTS_LEVEL_MSI)) &&
    + (msg[1].address_lo || msg[1].address_hi || msg[1].data));
    +}
    +
    /**
    * msi_domain_set_affinity - Generic affinity setter function for MSI domains
    * @irq_data: The irq data associated to the interrupt
    @@ -89,13 +102,14 @@ int msi_domain_set_affinity(struct irq_data *irq_data,
    const struct cpumask *mask, bool force)
    {
    struct irq_data *parent = irq_data->parent_data;
    - struct msi_msg msg;
    + struct msi_msg msg[2] = { [1] = { }, };
    int ret;

    ret = parent->chip->irq_set_affinity(parent, mask, force);
    if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
    - BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
    - irq_chip_write_msi_msg(irq_data, &msg);
    + BUG_ON(irq_chip_compose_msi_msg(irq_data, msg));
    + msi_check_level(irq_data->domain, msg);
    + irq_chip_write_msi_msg(irq_data, msg);
    }

    return ret;
    @@ -104,20 +118,21 @@ int msi_domain_set_affinity(struct irq_data *irq_data,
    static int msi_domain_activate(struct irq_domain *domain,
    struct irq_data *irq_data, bool early)
    {
    - struct msi_msg msg;
    + struct msi_msg msg[2] = { [1] = { }, };

    - BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
    - irq_chip_write_msi_msg(irq_data, &msg);
    + BUG_ON(irq_chip_compose_msi_msg(irq_data, msg));
    + msi_check_level(irq_data->domain, msg);
    + irq_chip_write_msi_msg(irq_data, msg);
    return 0;
    }

    static void msi_domain_deactivate(struct irq_domain *domain,
    struct irq_data *irq_data)
    {
    - struct msi_msg msg;
    + struct msi_msg msg[2];

    - memset(&msg, 0, sizeof(msg));
    - irq_chip_write_msi_msg(irq_data, &msg);
    + memset(msg, 0, sizeof(msg));
    + irq_chip_write_msi_msg(irq_data, msg);
    }

    static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
    \
     
     \ /
      Last update: 2018-05-13 16:04    [W:5.249 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site