From: wuyun.wu@huawei.com (Yun Wu (Abel))
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 09/13] irqchip: GICv3: ITS: MSI support
Date: Mon, 8 Dec 2014 11:28:15 +0800 [thread overview]
Message-ID: <54851ACF.2090204@huawei.com> (raw)
In-Reply-To: <1416839720-18400-10-git-send-email-marc.zyngier@arm.com>
Hi Marc,
On 2014/11/24 22:35, Marc Zyngier wrote:
> Now, the bit of code that allow us to use the ITS as a MSI controller.
> Both MSI and MSI-X are supported.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> drivers/irqchip/irq-gic-v3-its.c | 176 +++++++++++++++++++++++++++++++++++++
> include/linux/irqchip/arm-gic-v3.h | 6 ++
> 2 files changed, 182 insertions(+)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index d687fd4..532c6df 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -587,12 +587,47 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
> return IRQ_SET_MASK_OK_DONE;
> }
>
> +static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
> +{
> + struct its_device *its_dev = irq_data_get_irq_chip_data(d);
> + struct its_node *its;
> + u64 addr;
> +
> + its = its_dev->its;
> + addr = its->phys_base + GITS_TRANSLATER;
> +
> + msg->address_lo = addr & ((1UL << 32) - 1);
> + msg->address_hi = addr >> 32;
> + msg->data = its_get_event_id(d);
> +}
> +
> static struct irq_chip its_irq_chip = {
> .name = "ITS",
> .irq_mask = its_mask_irq,
> .irq_unmask = its_unmask_irq,
> .irq_eoi = its_eoi_irq,
> .irq_set_affinity = its_set_affinity,
> + .irq_compose_msi_msg = its_irq_compose_msi_msg,
> +};
> +
> +static void its_mask_msi_irq(struct irq_data *d)
> +{
> + pci_msi_mask_irq(d);
> + irq_chip_mask_parent(d);
> +}
> +
> +static void its_unmask_msi_irq(struct irq_data *d)
> +{
> + pci_msi_unmask_irq(d);
> + irq_chip_unmask_parent(d);
> +}
> +
> +static struct irq_chip its_msi_irq_chip = {
> + .name = "ITS-MSI",
> + .irq_unmask = its_unmask_msi_irq,
> + .irq_mask = its_mask_msi_irq,
> + .irq_eoi = irq_chip_eoi_parent,
> + .irq_write_msi_msg = pci_msi_domain_write_msg,
> };
>
> /*
> @@ -1055,3 +1090,144 @@ static void its_free_device(struct its_device *its_dev)
> kfree(its_dev->itt);
> kfree(its_dev);
> }
> +
> +static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
> +{
> + int idx;
> +
> + idx = find_first_zero_bit(dev->lpi_map, dev->nr_lpis);
> + if (idx == dev->nr_lpis)
> + return -ENOSPC;
> +
> + *hwirq = dev->lpi_base + idx;
> + set_bit(idx, dev->lpi_map);
> +
> + /* Map the GIC irq ID to the device */
> + its_send_mapvi(dev, *hwirq, idx);
It would be better if we do hardware-level initialization in domain.{activate,deactivate}.
> +
> + return 0;
> +}
> +
> +static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
> + int nvec, msi_alloc_info_t *info)
> +{
> + struct pci_dev *pdev;
> + struct its_node *its;
> + u32 dev_id;
> + struct its_device *its_dev;
> +
> + if (!dev_is_pci(dev))
> + return -EINVAL;
> +
> + pdev = to_pci_dev(dev);
> + dev_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
> + its = domain->parent->host_data;
> +
> + its_dev = its_find_device(its, dev_id);
> + if (WARN_ON(its_dev))
> + return -EINVAL;
> +
> + its_dev = its_create_device(its, dev_id, nvec);
> + if (!its_dev)
> + return -ENOMEM;
> +
> + dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n", nvec, ilog2(nvec));
> +
> + info->scratchpad[0].ptr = its_dev;
> + info->scratchpad[1].ptr = dev;
> + return 0;
> +}
> +
> +static struct msi_domain_ops its_pci_msi_ops = {
> + .msi_prepare = its_msi_prepare,
> +};
> +
> +static struct msi_domain_info its_pci_msi_domain_info = {
> + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
> + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
> + .ops = &its_pci_msi_ops,
> + .chip = &its_msi_irq_chip,
> +};
> +
> +static int its_irq_gic_domain_alloc(struct irq_domain *domain,
> + unsigned int virq,
> + irq_hw_number_t hwirq)
> +{
> + struct of_phandle_args args;
> +
> + args.np = domain->parent->of_node;
> + args.args_count = 3;
> + args.args[0] = GIC_IRQ_TYPE_LPI;
> + args.args[1] = hwirq;
> + args.args[2] = IRQ_TYPE_EDGE_RISING;
> +
> + return irq_domain_alloc_irqs_parent(domain, virq, 1, &args);
> +}
> +
> +static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> + unsigned int nr_irqs, void *args)
> +{
> + msi_alloc_info_t *info = args;
> + struct its_device *its_dev = info->scratchpad[0].ptr;
> + irq_hw_number_t hwirq;
> + int err;
> + int i;
> +
> + for (i = 0; i < nr_irqs; i++) {
> + err = its_alloc_device_irq(its_dev, &hwirq);
> + if (err)
> + return err;
> +
> + err = its_irq_gic_domain_alloc(domain, virq + i, hwirq);
> + if (err)
> + return err;
> +
> + irq_domain_set_hwirq_and_chip(domain, virq + i,
> + hwirq, &its_irq_chip, its_dev);
> + dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n",
> + (int)(hwirq - its_dev->lpi_base), (int)hwirq, virq + i);
> + }
> +
> + return 0;
> +}
> +
> +static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
> + unsigned int nr_irqs)
> +{
> + struct irq_data *d = irq_domain_get_irq_data(domain, virq);
> + struct its_device *its_dev = irq_data_get_irq_chip_data(d);
> + int i;
> +
> + for (i = 0; i < nr_irqs; i++) {
> + struct irq_data *data = irq_domain_get_irq_data(domain,
> + virq + i);
> + int event = its_get_event_id(data);
> +
> + /* Stop the delivery of interrupts */
> + its_send_discard(its_dev, event);
> +
> + /* Mark interrupt index as unused */
> + clear_bit(event, its_dev->lpi_map);
> +
> + /* Nuke the entry in the domain */
> + irq_domain_reset_irq_data(d);
I think you mean "data" here, instead of "d"?
Regards,
Abel
> + }
> +
> + /* If all interrupts have been freed, start mopping the floor */
> + if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
> + its_lpi_free(its_dev->lpi_map,
> + its_dev->lpi_base,
> + its_dev->nr_lpis);
> +
> + /* Unmap device/itt */
> + its_send_mapd(its_dev, 0);
> + its_free_device(its_dev);
> + }
> +
> + irq_domain_free_irqs_parent(domain, virq, nr_irqs);
> +}
> +
> +static const struct irq_domain_ops its_domain_ops = {
> + .alloc = its_irq_domain_alloc,
> + .free = its_irq_domain_free,
> +};
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 21c9d70..0ed30d7 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -295,6 +295,12 @@
>
> #include <linux/stringify.h>
>
> +/*
> + * We need a value to serve as a irq-type for LPIs. Choose one that will
> + * hopefully pique the interest of the reviewer.
> + */
> +#define GIC_IRQ_TYPE_LPI 0xa110c8ed
> +
> struct rdists {
> struct {
> void __iomem *rd_base;
WARNING: multiple messages have this Message-ID (diff)
From: "Yun Wu (Abel)" <wuyun.wu@huawei.com>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>,
Jason Cooper <jason@lakedaemon.net>,
<linux-arm-kernel@lists.infradead.org>,
<linux-kernel@vger.kernel.org>,
"Jiang Liu" <jiang.liu@linux.intel.com>,
Bjorn Helgaas <bhelgaas@google.com>,
"Yingjoe Chen" <yingjoe.chen@mediatek.com>,
Will Deacon <will.deacon@arm.com>,
"Catalin marinas" <catalin.marinas@arm.com>,
Mark Rutland <mark.rutland@arm.com>,
Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>,
Robert Richter <robert.richter@caviumnetworks.com>
Subject: Re: [PATCH v3 09/13] irqchip: GICv3: ITS: MSI support
Date: Mon, 8 Dec 2014 11:28:15 +0800 [thread overview]
Message-ID: <54851ACF.2090204@huawei.com> (raw)
In-Reply-To: <1416839720-18400-10-git-send-email-marc.zyngier@arm.com>
Hi Marc,
On 2014/11/24 22:35, Marc Zyngier wrote:
> Now, the bit of code that allow us to use the ITS as a MSI controller.
> Both MSI and MSI-X are supported.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> drivers/irqchip/irq-gic-v3-its.c | 176 +++++++++++++++++++++++++++++++++++++
> include/linux/irqchip/arm-gic-v3.h | 6 ++
> 2 files changed, 182 insertions(+)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index d687fd4..532c6df 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -587,12 +587,47 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
> return IRQ_SET_MASK_OK_DONE;
> }
>
> +static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
> +{
> + struct its_device *its_dev = irq_data_get_irq_chip_data(d);
> + struct its_node *its;
> + u64 addr;
> +
> + its = its_dev->its;
> + addr = its->phys_base + GITS_TRANSLATER;
> +
> + msg->address_lo = addr & ((1UL << 32) - 1);
> + msg->address_hi = addr >> 32;
> + msg->data = its_get_event_id(d);
> +}
> +
> static struct irq_chip its_irq_chip = {
> .name = "ITS",
> .irq_mask = its_mask_irq,
> .irq_unmask = its_unmask_irq,
> .irq_eoi = its_eoi_irq,
> .irq_set_affinity = its_set_affinity,
> + .irq_compose_msi_msg = its_irq_compose_msi_msg,
> +};
> +
> +static void its_mask_msi_irq(struct irq_data *d)
> +{
> + pci_msi_mask_irq(d);
> + irq_chip_mask_parent(d);
> +}
> +
> +static void its_unmask_msi_irq(struct irq_data *d)
> +{
> + pci_msi_unmask_irq(d);
> + irq_chip_unmask_parent(d);
> +}
> +
> +static struct irq_chip its_msi_irq_chip = {
> + .name = "ITS-MSI",
> + .irq_unmask = its_unmask_msi_irq,
> + .irq_mask = its_mask_msi_irq,
> + .irq_eoi = irq_chip_eoi_parent,
> + .irq_write_msi_msg = pci_msi_domain_write_msg,
> };
>
> /*
> @@ -1055,3 +1090,144 @@ static void its_free_device(struct its_device *its_dev)
> kfree(its_dev->itt);
> kfree(its_dev);
> }
> +
> +static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
> +{
> + int idx;
> +
> + idx = find_first_zero_bit(dev->lpi_map, dev->nr_lpis);
> + if (idx == dev->nr_lpis)
> + return -ENOSPC;
> +
> + *hwirq = dev->lpi_base + idx;
> + set_bit(idx, dev->lpi_map);
> +
> + /* Map the GIC irq ID to the device */
> + its_send_mapvi(dev, *hwirq, idx);
It would be better if we do hardware-level initialization in domain.{activate,deactivate}.
> +
> + return 0;
> +}
> +
> +static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
> + int nvec, msi_alloc_info_t *info)
> +{
> + struct pci_dev *pdev;
> + struct its_node *its;
> + u32 dev_id;
> + struct its_device *its_dev;
> +
> + if (!dev_is_pci(dev))
> + return -EINVAL;
> +
> + pdev = to_pci_dev(dev);
> + dev_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
> + its = domain->parent->host_data;
> +
> + its_dev = its_find_device(its, dev_id);
> + if (WARN_ON(its_dev))
> + return -EINVAL;
> +
> + its_dev = its_create_device(its, dev_id, nvec);
> + if (!its_dev)
> + return -ENOMEM;
> +
> + dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n", nvec, ilog2(nvec));
> +
> + info->scratchpad[0].ptr = its_dev;
> + info->scratchpad[1].ptr = dev;
> + return 0;
> +}
> +
> +static struct msi_domain_ops its_pci_msi_ops = {
> + .msi_prepare = its_msi_prepare,
> +};
> +
> +static struct msi_domain_info its_pci_msi_domain_info = {
> + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
> + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
> + .ops = &its_pci_msi_ops,
> + .chip = &its_msi_irq_chip,
> +};
> +
> +static int its_irq_gic_domain_alloc(struct irq_domain *domain,
> + unsigned int virq,
> + irq_hw_number_t hwirq)
> +{
> + struct of_phandle_args args;
> +
> + args.np = domain->parent->of_node;
> + args.args_count = 3;
> + args.args[0] = GIC_IRQ_TYPE_LPI;
> + args.args[1] = hwirq;
> + args.args[2] = IRQ_TYPE_EDGE_RISING;
> +
> + return irq_domain_alloc_irqs_parent(domain, virq, 1, &args);
> +}
> +
> +static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
> + unsigned int nr_irqs, void *args)
> +{
> + msi_alloc_info_t *info = args;
> + struct its_device *its_dev = info->scratchpad[0].ptr;
> + irq_hw_number_t hwirq;
> + int err;
> + int i;
> +
> + for (i = 0; i < nr_irqs; i++) {
> + err = its_alloc_device_irq(its_dev, &hwirq);
> + if (err)
> + return err;
> +
> + err = its_irq_gic_domain_alloc(domain, virq + i, hwirq);
> + if (err)
> + return err;
> +
> + irq_domain_set_hwirq_and_chip(domain, virq + i,
> + hwirq, &its_irq_chip, its_dev);
> + dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n",
> + (int)(hwirq - its_dev->lpi_base), (int)hwirq, virq + i);
> + }
> +
> + return 0;
> +}
> +
> +static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
> + unsigned int nr_irqs)
> +{
> + struct irq_data *d = irq_domain_get_irq_data(domain, virq);
> + struct its_device *its_dev = irq_data_get_irq_chip_data(d);
> + int i;
> +
> + for (i = 0; i < nr_irqs; i++) {
> + struct irq_data *data = irq_domain_get_irq_data(domain,
> + virq + i);
> + int event = its_get_event_id(data);
> +
> + /* Stop the delivery of interrupts */
> + its_send_discard(its_dev, event);
> +
> + /* Mark interrupt index as unused */
> + clear_bit(event, its_dev->lpi_map);
> +
> + /* Nuke the entry in the domain */
> + irq_domain_reset_irq_data(d);
I think you mean "data" here, instead of "d"?
Regards,
Abel
> + }
> +
> + /* If all interrupts have been freed, start mopping the floor */
> + if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
> + its_lpi_free(its_dev->lpi_map,
> + its_dev->lpi_base,
> + its_dev->nr_lpis);
> +
> + /* Unmap device/itt */
> + its_send_mapd(its_dev, 0);
> + its_free_device(its_dev);
> + }
> +
> + irq_domain_free_irqs_parent(domain, virq, nr_irqs);
> +}
> +
> +static const struct irq_domain_ops its_domain_ops = {
> + .alloc = its_irq_domain_alloc,
> + .free = its_irq_domain_free,
> +};
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 21c9d70..0ed30d7 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -295,6 +295,12 @@
>
> #include <linux/stringify.h>
>
> +/*
> + * We need a value to serve as a irq-type for LPIs. Choose one that will
> + * hopefully pique the interest of the reviewer.
> + */
> +#define GIC_IRQ_TYPE_LPI 0xa110c8ed
> +
> struct rdists {
> struct {
> void __iomem *rd_base;
next prev parent reply other threads:[~2014-12-08 3:28 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-24 14:35 [PATCH v3 00/13] arm64: PCI/MSI: GICv3 ITS support (stacked domain edition) Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 01/13] arm64: PCI/MSI: Use asm-generic/msi.h Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 02/13] irqchip: GICv3: Convert to domain hierarchy Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 03/13] irqchip: GICv3: rework redistributor structure Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 04/13] irqchip: GICv3: ITS command queue Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-12-10 3:03 ` Yun Wu (Abel)
2014-12-10 3:03 ` Yun Wu (Abel)
2014-12-10 11:20 ` Marc Zyngier
2014-12-10 11:20 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 05/13] irqchip: GICv3: ITS: irqchip implementation Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 06/13] irqchip: GICv3: ITS: LPI allocator Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:57 ` Jiang Liu
2014-11-24 14:57 ` Jiang Liu
2014-11-24 15:32 ` Marc Zyngier
2014-11-24 15:32 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 07/13] irqchip: GICv3: ITS: tables allocators Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 08/13] irqchip: GICv3: ITS: device allocation and configuration Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 09/13] irqchip: GICv3: ITS: MSI support Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-12-04 21:52 ` Stuart Yoder
2014-12-04 21:52 ` Stuart Yoder
2014-12-04 21:58 ` Thomas Gleixner
2014-12-04 21:58 ` Thomas Gleixner
2014-12-05 10:10 ` Marc Zyngier
2014-12-05 10:10 ` Marc Zyngier
2014-12-08 3:28 ` Yun Wu (Abel) [this message]
2014-12-08 3:28 ` Yun Wu (Abel)
2014-12-08 9:32 ` Marc Zyngier
2014-12-08 9:32 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 10/13] irqchip: GICv3: ITS: DT probing and initialization Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-25 21:08 ` Stuart Yoder
2014-11-25 21:08 ` Stuart Yoder
2014-11-26 10:14 ` Marc Zyngier
2014-11-26 10:14 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 11/13] irqchip: GICv3: ITS: plug ITS init into main GICv3 code Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 12/13] irqchip: GICv3: ITS: enable compilation of the ITS driver Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 13/13] irqchip: GICv3: Binding updates for ITS Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-26 8:06 ` [PATCH v3 00/13] arm64: PCI/MSI: GICv3 ITS support (stacked domain edition) Jason Cooper
2014-11-26 8:06 ` Jason Cooper
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54851ACF.2090204@huawei.com \
--to=wuyun.wu@huawei.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.