linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/5] Support managed interrupts for platform devices
@ 2020-11-25 17:20 John Garry
  2020-11-25 17:20 ` [PATCH v3 1/5] genirq/affinity: Add irq_update_affinity_desc() John Garry
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: John Garry @ 2020-11-25 17:20 UTC (permalink / raw)
  To: jejb, martin.petersen, lenb, rjw, gregkh, tglx
  Cc: linux-scsi, linux-kernel, linuxarm, linux-acpi, maz, John Garry

So far, managed interrupts are only used for PCI MSIs. This series adds
platform device support for managed interrupts. Initially this topic was
discussed at [0].

The method to enable managed interrupts is to allocate a group of IRQs for
the device, and then switch the interrupts to managed - this is done
through new function irq_update_affinity_desc().

Function devm_platform_get_irqs_affinity() is added as a helper to manage
this work, such that we don't need to export irq_update_affinity_desc() or
irq_create_affinity_masks().

In the devm_platform_get_irqs_affinity() release call a new platform
method is used to "put" an irq. The reason for this is that per-irq
mapping (and irq_desc) needs to be recreated anew for re-probing the LLDD,
such that we don't attempt to reconfigure the managed or any other flag
for an irq_desc.

For now, the HiSilicon SAS v2 hw driver is switched over. This is used
in the D05 dev board.

Performance gain observed for 6x SAS SSDs is ~357K -> 420K IOPs for fio read.

[0] https://lore.kernel.org/lkml/84a9411b-4ae3-1928-3d35-1666f2687ec8@huawei.com/

Changes since v2:
- Update genirq change as follows:
 - Handle when the irq is started, active, or already managed
 - Reject update when CONFIG_GENERIC_IRQ_RESERVATION_MODE is set
- Revamp platform.c API as follows:
 - Make it devm type
 - Add platform_put_irq() and associated change in ACPI code to allow irq
   resource to be reset
 - Unmap irqs for driver removal
 - Change API to accept min and max vectors

John Garry (5):
  genirq/affinity: Add irq_update_affinity_desc()
  ACPI: Make acpi_dev_irqresource_disabled() public
  driver core: platform: Add platform_put_irq()
  Driver core: platform: Add devm_platform_get_irqs_affinity()
  scsi: hisi_sas: Expose HW queues for v2 hw

 drivers/acpi/resource.c                |   2 +-
 drivers/base/platform.c                | 126 +++++++++++++++++++++++++
 drivers/scsi/hisi_sas/hisi_sas.h       |   4 +
 drivers/scsi/hisi_sas/hisi_sas_main.c  |  11 +++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |  68 ++++++++++---
 include/linux/acpi.h                   |   5 +
 include/linux/interrupt.h              |   8 ++
 include/linux/platform_device.h        |   6 ++
 kernel/irq/manage.c                    |  63 +++++++++++++
 9 files changed, 279 insertions(+), 14 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 1/5] genirq/affinity: Add irq_update_affinity_desc()
  2020-11-25 17:20 [PATCH v3 0/5] Support managed interrupts for platform devices John Garry
@ 2020-11-25 17:20 ` John Garry
  2020-11-26  8:51   ` Daniel Wagner
  2020-11-25 17:20 ` [PATCH v3 2/5] ACPI: Make acpi_dev_irqresource_disabled() public John Garry
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: John Garry @ 2020-11-25 17:20 UTC (permalink / raw)
  To: jejb, martin.petersen, lenb, rjw, gregkh, tglx
  Cc: linux-scsi, linux-kernel, linuxarm, linux-acpi, maz, John Garry

Add a function to allow the affinity of an interrupt be switched to
managed, such that interrupts allocated for platform devices may be
managed.

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Garry <john.garry@huawei.com>
---
 include/linux/interrupt.h |  8 +++++
 kernel/irq/manage.c       | 63 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index ee8299eb1f52..870b3251e174 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -352,6 +352,8 @@ extern int irq_can_set_affinity(unsigned int irq);
 extern int irq_select_affinity(unsigned int irq);
 
 extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);
+extern int irq_update_affinity_desc(unsigned int irq,
+				    struct irq_affinity_desc *affinity);
 
 extern int
 irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
@@ -387,6 +389,12 @@ static inline int irq_set_affinity_hint(unsigned int irq,
 	return -EINVAL;
 }
 
+static inline int irq_update_affinity_desc(unsigned int irq,
+					   struct irq_affinity_desc *affinity)
+{
+	return -EINVAL;
+}
+
 static inline int
 irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
 {
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index c460e0496006..8201aff639f7 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -371,6 +371,69 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
 	return ret;
 }
 
+/**
+ * irq_update_affinity_desc - Update affinity management for an interrupt
+ * @irq:	The interrupt number to update
+ * @affinity:	Pointer to the affinity descriptor
+ *
+ * This interface can be used to configure the affinity management of
+ * interrupts which have been allocated already.
+ */
+int irq_update_affinity_desc(unsigned int irq,
+			     struct irq_affinity_desc *affinity)
+{
+	struct irq_desc *desc;
+	unsigned long flags;
+	bool activated;
+	int ret = 0;
+
+	/*
+	 * Supporting this with the reservation scheme used by x86 needs
+	 * some more thought. Fail it for now.
+	 */
+	if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
+		return -EOPNOTSUPP;
+
+	desc = irq_get_desc_buslock(irq, &flags, 0);
+	if (!desc)
+		return -EINVAL;
+
+	/* Requires the interrupt to be shut down */
+	if (irqd_is_started(&desc->irq_data)) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
+	/* Interrupts which are already managed cannot be modified */
+	if (irqd_affinity_is_managed(&desc->irq_data)) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
+	/*
+	 * Deactivate the interrupt. That's required to undo
+	 * anything an earlier activation has established.
+	 */
+	activated = irqd_is_activated(&desc->irq_data);
+	if (activated)
+		irq_domain_deactivate_irq(&desc->irq_data);
+
+	if (affinity->is_managed) {
+		irqd_set(&desc->irq_data, IRQD_AFFINITY_MANAGED);
+		irqd_set(&desc->irq_data, IRQD_MANAGED_SHUTDOWN);
+	}
+
+	cpumask_copy(desc->irq_common_data.affinity, &affinity->mask);
+
+	/* Restore the activation state */
+	if (activated)
+		irq_domain_deactivate_irq(&desc->irq_data);
+
+out_unlock:
+	irq_put_desc_busunlock(desc, flags);
+	return ret;
+}
+
 int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force)
 {
 	struct irq_desc *desc = irq_to_desc(irq);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 2/5] ACPI: Make acpi_dev_irqresource_disabled() public
  2020-11-25 17:20 [PATCH v3 0/5] Support managed interrupts for platform devices John Garry
  2020-11-25 17:20 ` [PATCH v3 1/5] genirq/affinity: Add irq_update_affinity_desc() John Garry
@ 2020-11-25 17:20 ` John Garry
  2020-11-25 17:43   ` Rafael J. Wysocki
  2020-11-25 17:20 ` [PATCH v3 3/5] driver core: platform: Add platform_put_irq() John Garry
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: John Garry @ 2020-11-25 17:20 UTC (permalink / raw)
  To: jejb, martin.petersen, lenb, rjw, gregkh, tglx
  Cc: linux-scsi, linux-kernel, linuxarm, linux-acpi, maz, John Garry

To allow the platform device to "put" an irq, make the function to reset
an ACPI companion device irq resource public.

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/acpi/resource.c | 2 +-
 include/linux/acpi.h    | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index ad04824ca3ba..0999a98cab3c 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -380,7 +380,7 @@ unsigned int acpi_dev_get_irq_type(int triggering, int polarity)
 }
 EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type);
 
-static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
+void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
 {
 	res->start = gsi;
 	res->end = gsi;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 39263c6b52e1..d5101e36a645 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -467,6 +467,7 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
 					 struct resource_win *win);
 unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable);
 unsigned int acpi_dev_get_irq_type(int triggering, int polarity);
+void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi);
 bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
 				 struct resource *res);
 
@@ -939,6 +940,10 @@ static inline struct acpi_device *acpi_resource_consumer(struct resource *res)
 	return NULL;
 }
 
+static inline void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
+{
+}
+
 #endif	/* !CONFIG_ACPI */
 
 #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 3/5] driver core: platform: Add platform_put_irq()
  2020-11-25 17:20 [PATCH v3 0/5] Support managed interrupts for platform devices John Garry
  2020-11-25 17:20 ` [PATCH v3 1/5] genirq/affinity: Add irq_update_affinity_desc() John Garry
  2020-11-25 17:20 ` [PATCH v3 2/5] ACPI: Make acpi_dev_irqresource_disabled() public John Garry
@ 2020-11-25 17:20 ` John Garry
  2020-11-26  9:28   ` Marc Zyngier
  2020-11-25 17:20 ` [PATCH v3 4/5] Driver core: platform: Add devm_platform_get_irqs_affinity() John Garry
  2020-11-25 17:20 ` [PATCH v3 5/5] scsi: hisi_sas: Expose HW queues for v2 hw John Garry
  4 siblings, 1 reply; 13+ messages in thread
From: John Garry @ 2020-11-25 17:20 UTC (permalink / raw)
  To: jejb, martin.petersen, lenb, rjw, gregkh, tglx
  Cc: linux-scsi, linux-kernel, linuxarm, linux-acpi, maz, John Garry

Add a function to tear down the work which was done in platform_get_irq()
for when the device driver is done with the irq.

For ACPI companion devices the irq resource is set as disabled, as this
resource is configured from platform_get_irq()->acpi_irq_get() and requires
resetting.

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/base/platform.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 88aef93eb4dd..3eeda3746701 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -289,6 +289,20 @@ int platform_irq_count(struct platform_device *dev)
 }
 EXPORT_SYMBOL_GPL(platform_irq_count);
 
+void platform_put_irq(struct platform_device *dev, unsigned int num)
+{
+	unsigned int virq = platform_get_irq(dev, num);
+
+	irq_dispose_mapping(virq);
+	if (has_acpi_companion(&dev->dev)) {
+		struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ,
+							   num);
+
+		if (r)
+			acpi_dev_irqresource_disabled(r, 0);
+	}
+}
+
 /**
  * platform_get_resource_byname - get a resource for a device by name
  * @dev: platform device
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 4/5] Driver core: platform: Add devm_platform_get_irqs_affinity()
  2020-11-25 17:20 [PATCH v3 0/5] Support managed interrupts for platform devices John Garry
                   ` (2 preceding siblings ...)
  2020-11-25 17:20 ` [PATCH v3 3/5] driver core: platform: Add platform_put_irq() John Garry
@ 2020-11-25 17:20 ` John Garry
  2020-11-25 17:20 ` [PATCH v3 5/5] scsi: hisi_sas: Expose HW queues for v2 hw John Garry
  4 siblings, 0 replies; 13+ messages in thread
From: John Garry @ 2020-11-25 17:20 UTC (permalink / raw)
  To: jejb, martin.petersen, lenb, rjw, gregkh, tglx
  Cc: linux-scsi, linux-kernel, linuxarm, linux-acpi, maz, John Garry

Drivers for multi-queue platform devices may also want managed interrupts
for handling HW queue completion interrupts, so add support.

The function accepts an affinity descriptor pointer, which covers a set
of irqs for the device.

The reason a devm method is added - as opposed to non-devm - is because the
only current in-tree user will also use devm method for requesting the
interrupts; as such, the function is made as devm as it can ensure ordering
of freeing the irq and disposing of the mapping.

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/base/platform.c         | 114 +++++++++++++++++++++++++++++++-
 include/linux/platform_device.h |   6 ++
 2 files changed, 119 insertions(+), 1 deletion(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3eeda3746701..08f4175c4ac8 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -15,6 +15,7 @@
 #include <linux/of_irq.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/memblock.h>
 #include <linux/err.h>
@@ -289,7 +290,7 @@ int platform_irq_count(struct platform_device *dev)
 }
 EXPORT_SYMBOL_GPL(platform_irq_count);
 
-void platform_put_irq(struct platform_device *dev, unsigned int num)
+static void platform_put_irq(struct platform_device *dev, unsigned int num)
 {
 	unsigned int virq = platform_get_irq(dev, num);
 
@@ -303,6 +304,117 @@ void platform_put_irq(struct platform_device *dev, unsigned int num)
 	}
 }
 
+struct irq_affinity_devres {
+	unsigned int count;
+	void *dev_id;
+	unsigned int irq[];
+};
+
+static void devm_platform_get_irqs_affinity_release(struct device *dev,
+						    void *res)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct irq_affinity_devres *ptr = res;
+	int i;
+
+	for (i = 0; i < ptr->count; i++)
+		platform_put_irq(pdev, i);
+}
+
+/**
+ * devm_platform_get_irqs_affinity - devm method to get a set of IRQs for a
+ *				device using an interrupt affinity descriptor
+ * @dev: platform device pointer
+ * @affd: affinity descriptor
+ * @minvec: minimum count of interrupt vectors
+ * @maxvec: maximum count of interrupt vectors
+ * @irqs: pointer holder for IRQ numbers
+ *
+ * Gets a set of IRQs for a platform device, and updates IRQ afffinty according
+ * to the passed affinity descriptor
+ *
+ * Return: Number of vectors on success, negative error number on failure.
+ */
+int devm_platform_get_irqs_affinity(struct platform_device *dev,
+				    struct irq_affinity *affd,
+				    unsigned int minvec,
+				    unsigned int maxvec,
+				    int **irqs)
+{
+	struct irq_affinity_devres *ptr;
+	struct irq_affinity_desc *desc;
+	size_t size;
+	int i, ret, nvec;
+
+	if (!affd)
+		return -EPERM;
+
+	if (maxvec < minvec)
+		return -ERANGE;
+
+	nvec = platform_irq_count(dev);
+
+	if (nvec < minvec)
+		return -ENOSPC;
+
+	if (nvec <= affd->pre_vectors + affd->post_vectors)
+		return -EIO;
+
+	nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
+	if (nvec < minvec)
+		return -ENOSPC;
+
+	if (nvec > maxvec)
+		nvec = maxvec;
+
+	size = sizeof(*ptr) + sizeof(unsigned int) * nvec;
+	ptr = devres_alloc(devm_platform_get_irqs_affinity_release, size,
+			   GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	ptr->count = nvec;
+
+	for (i = 0; i < nvec; i++) {
+		int irq = platform_get_irq(dev, i);
+		if (irq < 0) {
+			ret = irq;
+			goto err_free_devres;
+		}
+		ptr->irq[i] = irq;
+	}
+
+	desc = irq_create_affinity_masks(nvec, affd);
+	if (!desc) {
+		ret = -ENOMEM;
+		goto err_free_devres;
+	}
+
+	for (i = 0; i < nvec; i++) {
+		ret = irq_update_affinity_desc(ptr->irq[i], &desc[i]);
+		if (ret) {
+			dev_err(&dev->dev, "failed to update irq%d affinity descriptor (%d)\n",
+				ptr->irq[i], ret);
+			goto err_free_desc;
+		}
+	}
+
+	devres_add(&dev->dev, ptr);
+
+	kfree(desc);
+
+	*irqs = ptr->irq;
+
+	return nvec;
+
+err_free_desc:
+	kfree(desc);
+err_free_devres:
+	devres_free(ptr);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devm_platform_get_irqs_affinity);
+
 /**
  * platform_get_resource_byname - get a resource for a device by name
  * @dev: platform device
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 77a2aada106d..4d75633e6735 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -15,6 +15,7 @@
 #define PLATFORM_DEVID_NONE	(-1)
 #define PLATFORM_DEVID_AUTO	(-2)
 
+struct irq_affinity;
 struct mfd_cell;
 struct property_entry;
 struct platform_device_id;
@@ -70,6 +71,11 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,
 extern int platform_get_irq(struct platform_device *, unsigned int);
 extern int platform_get_irq_optional(struct platform_device *, unsigned int);
 extern int platform_irq_count(struct platform_device *);
+extern int devm_platform_get_irqs_affinity(struct platform_device *dev,
+					   struct irq_affinity *affd,
+					   unsigned int minvec,
+					   unsigned int maxvec,
+					   int **irqs);
 extern struct resource *platform_get_resource_byname(struct platform_device *,
 						     unsigned int,
 						     const char *);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 5/5] scsi: hisi_sas: Expose HW queues for v2 hw
  2020-11-25 17:20 [PATCH v3 0/5] Support managed interrupts for platform devices John Garry
                   ` (3 preceding siblings ...)
  2020-11-25 17:20 ` [PATCH v3 4/5] Driver core: platform: Add devm_platform_get_irqs_affinity() John Garry
@ 2020-11-25 17:20 ` John Garry
  4 siblings, 0 replies; 13+ messages in thread
From: John Garry @ 2020-11-25 17:20 UTC (permalink / raw)
  To: jejb, martin.petersen, lenb, rjw, gregkh, tglx
  Cc: linux-scsi, linux-kernel, linuxarm, linux-acpi, maz, John Garry

As a performance enhancement, make the completion queue interrupts managed.

In addition, in commit bf0beec0607d ("blk-mq: drain I/O when all CPUs in a
hctx are offline"), CPU hotplug for MQ devices using managed interrupts
is made safe. So expose HW queues to blk-mq to take advantage of this.

Flag Scsi_host.host_tagset is also set to ensure that the HBA is not sent
more commands than it can handle. However the driver still does not use
request tag for IPTT as there are many HW bugs means that special rules
apply for IPTT allocation.

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |  4 ++
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 11 +++++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 68 +++++++++++++++++++++-----
 3 files changed, 70 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index a25cfc11c96d..aa67807c5693 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -14,6 +14,7 @@
 #include <linux/debugfs.h>
 #include <linux/dmapool.h>
 #include <linux/iopoll.h>
+#include <linux/irq.h>
 #include <linux/lcm.h>
 #include <linux/libata.h>
 #include <linux/mfd/syscon.h>
@@ -312,6 +313,7 @@ enum {
 
 struct hisi_sas_hw {
 	int (*hw_init)(struct hisi_hba *hisi_hba);
+	int (*interrupt_preinit)(struct hisi_hba *hisi_hba);
 	void (*setup_itct)(struct hisi_hba *hisi_hba,
 			   struct hisi_sas_device *device);
 	int (*slot_index_alloc)(struct hisi_hba *hisi_hba,
@@ -418,6 +420,8 @@ struct hisi_hba {
 	u32 refclk_frequency_mhz;
 	u8 sas_addr[SAS_ADDR_SIZE];
 
+	int *irq_map; /* v2 hw */
+
 	int n_phy;
 	spinlock_t lock;
 	struct semaphore sem;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index c8dd8588f800..624c5ec723fb 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -2614,6 +2614,13 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
 	return NULL;
 }
 
+static int hisi_sas_interrupt_preinit(struct hisi_hba *hisi_hba)
+{
+	if (hisi_hba->hw->interrupt_preinit)
+		return hisi_hba->hw->interrupt_preinit(hisi_hba);
+	return 0;
+}
+
 int hisi_sas_probe(struct platform_device *pdev,
 		   const struct hisi_sas_hw *hw)
 {
@@ -2671,6 +2678,10 @@ int hisi_sas_probe(struct platform_device *pdev,
 		sha->sas_port[i] = &hisi_hba->port[i].sas_port;
 	}
 
+	rc = hisi_sas_interrupt_preinit(hisi_hba);
+	if (rc)
+		goto err_out_ha;
+
 	rc = scsi_add_host(shost, &pdev->dev);
 	if (rc)
 		goto err_out_ha;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index b57177b52fac..6ad486e49468 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -3302,6 +3302,30 @@ static irq_handler_t fatal_interrupts[HISI_SAS_FATAL_INT_NR] = {
 	fatal_axi_int_v2_hw
 };
 
+#define CQ0_IRQ_INDEX (96)
+
+static int hisi_sas_v2_interrupt_preinit(struct hisi_hba *hisi_hba)
+{
+	struct platform_device *pdev = hisi_hba->platform_dev;
+	struct Scsi_Host *shost = hisi_hba->shost;
+	int nvec, *irqs;
+	struct irq_affinity desc = {
+		.pre_vectors = CQ0_IRQ_INDEX,
+	};
+
+	nvec = devm_platform_get_irqs_affinity(pdev, &desc, CQ0_IRQ_INDEX + 1,
+					CQ0_IRQ_INDEX + hisi_hba->queue_count,
+					&hisi_hba->irq_map);
+	if (nvec < 0)
+		return nvec;
+
+	shost->nr_hw_queues = hisi_hba->cq_nvecs = nvec - 96;
+
+	kfree(irqs);
+
+	return 0;
+}
+
 /*
  * There is a limitation in the hip06 chipset that we need
  * to map in all mbigen interrupts, even if they are not used.
@@ -3310,14 +3334,11 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
 {
 	struct platform_device *pdev = hisi_hba->platform_dev;
 	struct device *dev = &pdev->dev;
-	int irq, rc = 0, irq_map[128];
+	int irq, rc = 0;
 	int i, phy_no, fatal_no, queue_no;
 
-	for (i = 0; i < 128; i++)
-		irq_map[i] = platform_get_irq(pdev, i);
-
 	for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) {
-		irq = irq_map[i + 1]; /* Phy up/down is irq1 */
+		irq = hisi_hba->irq_map[i + 1]; /* Phy up/down is irq1 */
 		rc = devm_request_irq(dev, irq, phy_interrupts[i], 0,
 				      DRV_NAME " phy", hisi_hba);
 		if (rc) {
@@ -3331,7 +3352,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
 	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
 		struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 
-		irq = irq_map[phy_no + 72];
+		irq = hisi_hba->irq_map[phy_no + 72];
 		rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0,
 				      DRV_NAME " sata", phy);
 		if (rc) {
@@ -3343,7 +3364,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
 	}
 
 	for (fatal_no = 0; fatal_no < HISI_SAS_FATAL_INT_NR; fatal_no++) {
-		irq = irq_map[fatal_no + 81];
+		irq = hisi_hba->irq_map[fatal_no + 81];
 		rc = devm_request_irq(dev, irq, fatal_interrupts[fatal_no], 0,
 				      DRV_NAME " fatal", hisi_hba);
 		if (rc) {
@@ -3354,24 +3375,22 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
 		}
 	}
 
-	for (queue_no = 0; queue_no < hisi_hba->queue_count; queue_no++) {
+	for (queue_no = 0; queue_no < hisi_hba->cq_nvecs; queue_no++) {
 		struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
 
-		cq->irq_no = irq_map[queue_no + 96];
+		cq->irq_no = hisi_hba->irq_map[queue_no + 96];
 		rc = devm_request_threaded_irq(dev, cq->irq_no,
 					       cq_interrupt_v2_hw,
 					       cq_thread_v2_hw, IRQF_ONESHOT,
 					       DRV_NAME " cq", cq);
 		if (rc) {
 			dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
-				irq, rc);
+					cq->irq_no, rc);
 			rc = -ENOENT;
 			goto err_out;
 		}
+		cq->irq_mask = irq_get_affinity_mask(cq->irq_no);
 	}
-
-	hisi_hba->cq_nvecs = hisi_hba->queue_count;
-
 err_out:
 	return rc;
 }
@@ -3529,6 +3548,26 @@ static struct device_attribute *host_attrs_v2_hw[] = {
 	NULL
 };
 
+static int map_queues_v2_hw(struct Scsi_Host *shost)
+{
+	struct hisi_hba *hisi_hba = shost_priv(shost);
+	struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
+	const struct cpumask *mask;
+	unsigned int queue, cpu;
+
+	for (queue = 0; queue < qmap->nr_queues; queue++) {
+		mask = irq_get_affinity_mask(hisi_hba->irq_map[96 + queue]);
+		if (!mask)
+			continue;
+
+		for_each_cpu(cpu, mask)
+			qmap->mq_map[cpu] = qmap->queue_offset + queue;
+	}
+
+	return 0;
+
+}
+
 static struct scsi_host_template sht_v2_hw = {
 	.name			= DRV_NAME,
 	.proc_name		= DRV_NAME,
@@ -3553,10 +3592,13 @@ static struct scsi_host_template sht_v2_hw = {
 #endif
 	.shost_attrs		= host_attrs_v2_hw,
 	.host_reset		= hisi_sas_host_reset,
+	.map_queues		= map_queues_v2_hw,
+	.host_tagset		= 1,
 };
 
 static const struct hisi_sas_hw hisi_sas_v2_hw = {
 	.hw_init = hisi_sas_v2_init,
+	.interrupt_preinit = hisi_sas_v2_interrupt_preinit,
 	.setup_itct = setup_itct_v2_hw,
 	.slot_index_alloc = slot_index_alloc_quirk_v2_hw,
 	.alloc_dev = alloc_dev_quirk_v2_hw,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/5] ACPI: Make acpi_dev_irqresource_disabled() public
  2020-11-25 17:20 ` [PATCH v3 2/5] ACPI: Make acpi_dev_irqresource_disabled() public John Garry
@ 2020-11-25 17:43   ` Rafael J. Wysocki
  2020-11-26  8:49     ` John Garry
  0 siblings, 1 reply; 13+ messages in thread
From: Rafael J. Wysocki @ 2020-11-25 17:43 UTC (permalink / raw)
  To: John Garry
  Cc: James E.J. Bottomley, Martin K. Petersen, Len Brown,
	Rafael J. Wysocki, Greg Kroah-Hartman, Thomas Gleixner,
	open list:TARGET SUBSYSTEM, Linux Kernel Mailing List, Linuxarm,
	ACPI Devel Maling List, Marc Zyngier

On Wed, Nov 25, 2020 at 6:25 PM John Garry <john.garry@huawei.com> wrote:
>
> To allow the platform device to "put" an irq, make the function to reset
> an ACPI companion device irq resource public.
>
> Signed-off-by: John Garry <john.garry@huawei.com>

I'd rather move it to kernel/resource.c as it is not ACPI-specific and
its only connection to ACPI is that it is used in the ACPI resources
management code.

> ---
>  drivers/acpi/resource.c | 2 +-
>  include/linux/acpi.h    | 5 +++++
>  2 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
> index ad04824ca3ba..0999a98cab3c 100644
> --- a/drivers/acpi/resource.c
> +++ b/drivers/acpi/resource.c
> @@ -380,7 +380,7 @@ unsigned int acpi_dev_get_irq_type(int triggering, int polarity)
>  }
>  EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type);
>
> -static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
> +void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
>  {
>         res->start = gsi;
>         res->end = gsi;
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 39263c6b52e1..d5101e36a645 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -467,6 +467,7 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
>                                          struct resource_win *win);
>  unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable);
>  unsigned int acpi_dev_get_irq_type(int triggering, int polarity);
> +void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi);
>  bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
>                                  struct resource *res);
>
> @@ -939,6 +940,10 @@ static inline struct acpi_device *acpi_resource_consumer(struct resource *res)
>         return NULL;
>  }
>
> +static inline void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
> +{
> +}
> +
>  #endif /* !CONFIG_ACPI */
>
>  #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
> --
> 2.26.2
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/5] ACPI: Make acpi_dev_irqresource_disabled() public
  2020-11-25 17:43   ` Rafael J. Wysocki
@ 2020-11-26  8:49     ` John Garry
  2020-11-26 14:24       ` Rafael J. Wysocki
  0 siblings, 1 reply; 13+ messages in thread
From: John Garry @ 2020-11-26  8:49 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: James E.J. Bottomley, Martin K. Petersen, Len Brown,
	Rafael J. Wysocki, Greg Kroah-Hartman, Thomas Gleixner,
	open list:TARGET SUBSYSTEM, Linux Kernel Mailing List, Linuxarm,
	ACPI Devel Maling List, Marc Zyngier

On 25/11/2020 17:43, Rafael J. Wysocki wrote:
> On Wed, Nov 25, 2020 at 6:25 PM John Garry<john.garry@huawei.com>  wrote:
>> To allow the platform device to "put" an irq, make the function to reset
>> an ACPI companion device irq resource public.
>>
>> Signed-off-by: John Garry<john.garry@huawei.com>
> I'd rather move it to kernel/resource.c as it is not ACPI-specific and
> its only connection to ACPI is that it is used in the ACPI resources
> management code.
> 

Hi Rafael,

That's ok, but we could also just put in include/linux/ioport.h as a 
static inline as it’s so small. Not so important, I guess.

And I'm not sure how this part could be merged, so maybe I can do as 2x 
patches now - 1. add resource.c function 2. remove ACPI duplicate. - so 
we have the option to merge ACPI part later if it makes things easier.

Thanks,
John

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 1/5] genirq/affinity: Add irq_update_affinity_desc()
  2020-11-25 17:20 ` [PATCH v3 1/5] genirq/affinity: Add irq_update_affinity_desc() John Garry
@ 2020-11-26  8:51   ` Daniel Wagner
  2020-11-26  8:54     ` John Garry
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Wagner @ 2020-11-26  8:51 UTC (permalink / raw)
  To: John Garry
  Cc: jejb, martin.petersen, lenb, rjw, gregkh, tglx, linux-scsi,
	linux-kernel, linuxarm, linux-acpi, maz

Hi John,

On Thu, Nov 26, 2020 at 01:20:37AM +0800, John Garry wrote:
> +	activated = irqd_is_activated(&desc->irq_data);
> +	if (activated)
> +		irq_domain_deactivate_irq(&desc->irq_data);
> +
> +	if (affinity->is_managed) {
> +		irqd_set(&desc->irq_data, IRQD_AFFINITY_MANAGED);
> +		irqd_set(&desc->irq_data, IRQD_MANAGED_SHUTDOWN);
> +	}
> +
> +	cpumask_copy(desc->irq_common_data.affinity, &affinity->mask);
> +
> +	/* Restore the activation state */
> +	if (activated)
> +		irq_domain_deactivate_irq(&desc->irq_data);

Shouldn't this be irq_domain_activate_irq() ?

Thanks,
Daniel



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 1/5] genirq/affinity: Add irq_update_affinity_desc()
  2020-11-26  8:51   ` Daniel Wagner
@ 2020-11-26  8:54     ` John Garry
  0 siblings, 0 replies; 13+ messages in thread
From: John Garry @ 2020-11-26  8:54 UTC (permalink / raw)
  To: Daniel Wagner
  Cc: jejb, martin.petersen, lenb, rjw, gregkh, tglx, linux-scsi,
	linux-kernel, linuxarm, linux-acpi, maz

Hi Daniel,

> 
> On Thu, Nov 26, 2020 at 01:20:37AM +0800, John Garry wrote:
>> +	activated = irqd_is_activated(&desc->irq_data);
>> +	if (activated)
>> +		irq_domain_deactivate_irq(&desc->irq_data);
>> +
>> +	if (affinity->is_managed) {
>> +		irqd_set(&desc->irq_data, IRQD_AFFINITY_MANAGED);
>> +		irqd_set(&desc->irq_data, IRQD_MANAGED_SHUTDOWN);
>> +	}
>> +
>> +	cpumask_copy(desc->irq_common_data.affinity, &affinity->mask);
>> +
>> +	/* Restore the activation state */
>> +	if (activated)
>> +		irq_domain_deactivate_irq(&desc->irq_data);
> Shouldn't this be irq_domain_activate_irq() ?

Yeah, I think so. Blushes.

Cheers,
John

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/5] driver core: platform: Add platform_put_irq()
  2020-11-25 17:20 ` [PATCH v3 3/5] driver core: platform: Add platform_put_irq() John Garry
@ 2020-11-26  9:28   ` Marc Zyngier
  2020-11-26 11:23     ` John Garry
  0 siblings, 1 reply; 13+ messages in thread
From: Marc Zyngier @ 2020-11-26  9:28 UTC (permalink / raw)
  To: John Garry
  Cc: jejb, martin.petersen, lenb, rjw, gregkh, tglx, linux-scsi,
	linux-kernel, linuxarm, linux-acpi

On 2020-11-25 17:20, John Garry wrote:
> Add a function to tear down the work which was done in 
> platform_get_irq()
> for when the device driver is done with the irq.
> 
> For ACPI companion devices the irq resource is set as disabled, as this
> resource is configured from platform_get_irq()->acpi_irq_get() and 
> requires
> resetting.
> 
> Signed-off-by: John Garry <john.garry@huawei.com>
> ---
>  drivers/base/platform.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index 88aef93eb4dd..3eeda3746701 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -289,6 +289,20 @@ int platform_irq_count(struct platform_device 
> *dev)
>  }
>  EXPORT_SYMBOL_GPL(platform_irq_count);
> 
> +void platform_put_irq(struct platform_device *dev, unsigned int num)
> +{
> +	unsigned int virq = platform_get_irq(dev, num);

I find it pretty odd to have to recompute the interrupt number,
which in turn results in a domain lookup. It things were refcounted
(they aren't yet), irq_dispose_mapping() would have no effect.

<pedant>
It also goes against the usual construct where if you obtain an object
based on some parameters, the release happens by specifying the object
itself, and not the parameters that lead to the object.
</pedant>

> +
> +	irq_dispose_mapping(virq);
> +	if (has_acpi_companion(&dev->dev)) {
> +		struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ,
> +							   num);
> +
> +		if (r)
> +			acpi_dev_irqresource_disabled(r, 0);

It looks to me that the ACPI thing is what needs to be promoted to a
first class function, releasing all the resources that have used by
a given device.

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/5] driver core: platform: Add platform_put_irq()
  2020-11-26  9:28   ` Marc Zyngier
@ 2020-11-26 11:23     ` John Garry
  0 siblings, 0 replies; 13+ messages in thread
From: John Garry @ 2020-11-26 11:23 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: jejb, martin.petersen, lenb, rjw, gregkh, tglx, linux-scsi,
	linux-kernel, linuxarm, linux-acpi

On 26/11/2020 09:28, Marc Zyngier wrote:
> On 2020-11-25 17:20, John Garry wrote:
>> Add a function to tear down the work which was done in platform_get_irq()
>> for when the device driver is done with the irq.
>>
>> For ACPI companion devices the irq resource is set as disabled, as this
>> resource is configured from platform_get_irq()->acpi_irq_get() and 
>> requires
>> resetting.
>>
>> Signed-off-by: John Garry <john.garry@huawei.com>
>> ---
>>  drivers/base/platform.c | 14 ++++++++++++++
>>  1 file changed, 14 insertions(+)
>>
>> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
>> index 88aef93eb4dd..3eeda3746701 100644
>> --- a/drivers/base/platform.c
>> +++ b/drivers/base/platform.c
>> @@ -289,6 +289,20 @@ int platform_irq_count(struct platform_device *dev)
>>  }
>>  EXPORT_SYMBOL_GPL(platform_irq_count);
>>

Hi Marc,

>> +void platform_put_irq(struct platform_device *dev, unsigned int num)
>> +{
>> +    unsigned int virq = platform_get_irq(dev, num);
> 
> I find it pretty odd to have to recompute the interrupt number,
> which in turn results in a domain lookup. 

Well we do have the virq available, but then we need to pass the virq 
and device irq index. But maybe I somehow reverse-lookup the ACPI res 
somehow from virq, such that we don't require the irq device index.

> It things were refcounted
> (they aren't yet), irq_dispose_mapping() would have no effect.
> 
> <pedant>
> It also goes against the usual construct where if you obtain an object
> based on some parameters, the release happens by specifying the object
> itself, and not the parameters that lead to the object.
> </pedant>

Yes, ideally we can use virq.

> 
>> +
>> +    irq_dispose_mapping(virq);
>> +    if (has_acpi_companion(&dev->dev)) {
>> +        struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ,
>> +                               num);
>> +
>> +        if (r)
>> +            acpi_dev_irqresource_disabled(r, 0);
> 
> It looks to me that the ACPI thing is what needs to be promoted to a
> first class function, releasing all the resources that have used by
> a given device.

This is just clearing the irq resource flags, but it could be reasonable 
(to promote).

Thanks,
John

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/5] ACPI: Make acpi_dev_irqresource_disabled() public
  2020-11-26  8:49     ` John Garry
@ 2020-11-26 14:24       ` Rafael J. Wysocki
  0 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2020-11-26 14:24 UTC (permalink / raw)
  To: John Garry
  Cc: Rafael J. Wysocki, James E.J. Bottomley, Martin K. Petersen,
	Len Brown, Rafael J. Wysocki, Greg Kroah-Hartman,
	Thomas Gleixner, open list:TARGET SUBSYSTEM,
	Linux Kernel Mailing List, Linuxarm, ACPI Devel Maling List,
	Marc Zyngier

On Thu, Nov 26, 2020 at 9:49 AM John Garry <john.garry@huawei.com> wrote:
>
> On 25/11/2020 17:43, Rafael J. Wysocki wrote:
> > On Wed, Nov 25, 2020 at 6:25 PM John Garry<john.garry@huawei.com>  wrote:
> >> To allow the platform device to "put" an irq, make the function to reset
> >> an ACPI companion device irq resource public.
> >>
> >> Signed-off-by: John Garry<john.garry@huawei.com>
> > I'd rather move it to kernel/resource.c as it is not ACPI-specific and
> > its only connection to ACPI is that it is used in the ACPI resources
> > management code.
> >
>
> Hi Rafael,
>
> That's ok, but we could also just put in include/linux/ioport.h as a
> static inline as it’s so small. Not so important, I guess.
>
> And I'm not sure how this part could be merged, so maybe I can do as 2x
> patches now - 1. add resource.c function 2. remove ACPI duplicate. - so
> we have the option to merge ACPI part later if it makes things easier.

That would work too.

My point really was that exporting that function from ACPI was rather confusing.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-11-26 14:25 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-25 17:20 [PATCH v3 0/5] Support managed interrupts for platform devices John Garry
2020-11-25 17:20 ` [PATCH v3 1/5] genirq/affinity: Add irq_update_affinity_desc() John Garry
2020-11-26  8:51   ` Daniel Wagner
2020-11-26  8:54     ` John Garry
2020-11-25 17:20 ` [PATCH v3 2/5] ACPI: Make acpi_dev_irqresource_disabled() public John Garry
2020-11-25 17:43   ` Rafael J. Wysocki
2020-11-26  8:49     ` John Garry
2020-11-26 14:24       ` Rafael J. Wysocki
2020-11-25 17:20 ` [PATCH v3 3/5] driver core: platform: Add platform_put_irq() John Garry
2020-11-26  9:28   ` Marc Zyngier
2020-11-26 11:23     ` John Garry
2020-11-25 17:20 ` [PATCH v3 4/5] Driver core: platform: Add devm_platform_get_irqs_affinity() John Garry
2020-11-25 17:20 ` [PATCH v3 5/5] scsi: hisi_sas: Expose HW queues for v2 hw John Garry

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).