* [patch V3 00/10] genirq/msi: Spring cleaning
@ 2025-03-17 13:29 Thomas Gleixner
2025-03-17 13:29 ` [patch V3 01/10] cleanup: Provide retain_ptr() Thomas Gleixner
` (9 more replies)
0 siblings, 10 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Nishanth Menon,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Bjorn Helgaas, linux-pci,
Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
linux-scsi, Jonathan Cameron
This is version 3 of the cleanup work. The previous version can be found
here:
https://lore.kernel.org/all/20250313130212.450198939@linutronix.de
While converting the MSI descriptor locking to a lock guard() I stumbled
over various abuse of MSI descriptors (again).
The following series cleans up the offending code and converts the MSI
descriptor locking over to lock guards.
Changes vs. V2:
- Use __free() in __msix_setup_interrupts() - PeterZ
- Fix a typo in the msi core code
- Collect Reviewed/Tested/Acked-by tags where appropriate
Patches 1, 3-4, 6-10 are unmodifed.
The series applies on:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/msi
and is available from git:
git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git irq/msi
Thanks,
tglx
---
drivers/ntb/msi.c | 22 +---
drivers/pci/controller/pci-hyperv.c | 14 --
drivers/pci/msi/api.c | 6 -
drivers/pci/msi/msi.c | 171 ++++++++++++++++++++++--------------
drivers/pci/pci.h | 9 +
drivers/pci/tph.c | 44 ---------
drivers/soc/ti/ti_sci_inta_msi.c | 10 --
drivers/ufs/host/ufs-qcom.c | 75 ++++++++-------
include/linux/cleanup.h | 17 +++
include/linux/irqdomain.h | 2
include/linux/msi.h | 7 +
kernel/irq/msi.c | 125 ++++++++++----------------
12 files changed, 249 insertions(+), 253 deletions(-)
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 01/10] cleanup: Provide retain_ptr()
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-17 13:57 ` James Bottomley
2025-03-17 13:29 ` [patch V3 02/10] genirq/msi: Use lock guards for MSI descriptor locking Thomas Gleixner
` (8 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Nishanth Menon,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Bjorn Helgaas, linux-pci,
Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
linux-scsi, Jonathan Cameron
In cases where an allocation is consumed by another function, the
allocation needs to be retained on success or freed on failure. The code
pattern is usually:
struct foo *f = kzalloc(sizeof(*f), GFP_KERNEL);
struct bar *b;
,,,
// Initialize f
...
if (ret)
goto free;
...
bar = bar_create(f);
if (!bar) {
ret = -ENOMEM;
goto free;
}
...
return 0;
free:
kfree(f);
return ret;
This prevents using __free(kfree) on @f because there is no canonical way
to tell the cleanup code that the allocation should not be freed.
Abusing no_free_ptr() by force ignoring the return value is not really a
sensible option either.
Provide an explicit macro retain_ptr(), which NULLs the cleanup
pointer. That makes it easy to analyze and reason about.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
---
include/linux/cleanup.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
--- a/include/linux/cleanup.h
+++ b/include/linux/cleanup.h
@@ -216,6 +216,23 @@ const volatile void * __must_check_fn(co
#define return_ptr(p) return no_free_ptr(p)
+/*
+ * Only for situations where an allocation is handed in to another function
+ * and consumed by that function on success.
+ *
+ * struct foo *f __free(kfree) = kzalloc(sizeof(*f), GFP_KERNEL);
+ *
+ * setup(f);
+ * if (some_condition)
+ * return -EINVAL;
+ * ....
+ * ret = bar(f);
+ * if (!ret)
+ * retain_ptr(f);
+ * return ret;
+ */
+#define retain_ptr(p) \
+ __get_and_null(p, NULL)
/*
* DEFINE_CLASS(name, type, exit, init, init_args...):
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 02/10] genirq/msi: Use lock guards for MSI descriptor locking
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
2025-03-17 13:29 ` [patch V3 01/10] cleanup: Provide retain_ptr() Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-17 13:29 ` [patch V3 03/10] soc: ti: ti_sci_inta_msi: Switch MSI descriptor locking to guard() Thomas Gleixner
` (7 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Nishanth Menon,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Bjorn Helgaas, linux-pci,
Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
linux-scsi, Jonathan Cameron
Provide a lock guard for MSI descriptor locking and update the core code
accordingly.
No functional change intended.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
V2: Remove the gotos - Jonathan
---
include/linux/irqdomain.h | 2
include/linux/msi.h | 3 +
kernel/irq/msi.c | 109 ++++++++++++++++------------------------------
3 files changed, 45 insertions(+), 69 deletions(-)
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -281,6 +281,8 @@ static inline struct fwnode_handle *irq_
void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
+DEFINE_FREE(irq_domain_free_fwnode, struct fwnode_handle *, if (_T) irq_domain_free_fwnode(_T))
+
struct irq_domain_chip_generic_info;
/**
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -227,6 +227,9 @@ int msi_setup_device_data(struct device
void msi_lock_descs(struct device *dev);
void msi_unlock_descs(struct device *dev);
+DEFINE_LOCK_GUARD_1(msi_descs_lock, struct device, msi_lock_descs(_T->lock),
+ msi_unlock_descs(_T->lock));
+
struct msi_desc *msi_domain_first_desc(struct device *dev, unsigned int domid,
enum msi_desc_filter filter);
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -443,7 +443,6 @@ EXPORT_SYMBOL_GPL(msi_next_desc);
unsigned int msi_domain_get_virq(struct device *dev, unsigned int domid, unsigned int index)
{
struct msi_desc *desc;
- unsigned int ret = 0;
bool pcimsi = false;
struct xarray *xa;
@@ -457,7 +456,7 @@ unsigned int msi_domain_get_virq(struct
if (dev_is_pci(dev) && domid == MSI_DEFAULT_DOMAIN)
pcimsi = to_pci_dev(dev)->msi_enabled;
- msi_lock_descs(dev);
+ guard(msi_descs_lock)(dev);
xa = &dev->msi.data->__domains[domid].store;
desc = xa_load(xa, pcimsi ? 0 : index);
if (desc && desc->irq) {
@@ -466,16 +465,12 @@ unsigned int msi_domain_get_virq(struct
* PCI-MSIX and platform MSI use a descriptor per
* interrupt.
*/
- if (pcimsi) {
- if (index < desc->nvec_used)
- ret = desc->irq + index;
- } else {
- ret = desc->irq;
- }
+ if (!pcimsi)
+ return desc->irq;
+ if (index < desc->nvec_used)
+ return desc->irq + index;
}
-
- msi_unlock_descs(dev);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(msi_domain_get_virq);
@@ -993,9 +988,8 @@ bool msi_create_device_irq_domain(struct
void *chip_data)
{
struct irq_domain *domain, *parent = dev->msi.domain;
- struct fwnode_handle *fwnode, *fwnalloced = NULL;
- struct msi_domain_template *bundle;
const struct msi_parent_ops *pops;
+ struct fwnode_handle *fwnode;
if (!irq_domain_is_msi_parent(parent))
return false;
@@ -1003,7 +997,8 @@ bool msi_create_device_irq_domain(struct
if (domid >= MSI_MAX_DEVICE_IRQDOMAINS)
return false;
- bundle = kmemdup(template, sizeof(*bundle), GFP_KERNEL);
+ struct msi_domain_template *bundle __free(kfree) =
+ kmemdup(template, sizeof(*bundle), GFP_KERNEL);
if (!bundle)
return false;
@@ -1026,41 +1021,36 @@ bool msi_create_device_irq_domain(struct
* node as they are not guaranteed to have a fwnode. They are never
* looked up and always handled in the context of the device.
*/
- if (bundle->info.flags & MSI_FLAG_USE_DEV_FWNODE)
- fwnode = dev->fwnode;
+ struct fwnode_handle *fwnode_alloced __free(irq_domain_free_fwnode) = NULL;
+
+ if (!(bundle->info.flags & MSI_FLAG_USE_DEV_FWNODE))
+ fwnode = fwnode_alloced = irq_domain_alloc_named_fwnode(bundle->name);
else
- fwnode = fwnalloced = irq_domain_alloc_named_fwnode(bundle->name);
+ fwnode = dev->fwnode;
if (!fwnode)
- goto free_bundle;
+ return false;
if (msi_setup_device_data(dev))
- goto free_fwnode;
-
- msi_lock_descs(dev);
+ return false;
+ guard(msi_descs_lock)(dev);
if (WARN_ON_ONCE(msi_get_device_domain(dev, domid)))
- goto fail;
+ return false;
if (!pops->init_dev_msi_info(dev, parent, parent, &bundle->info))
- goto fail;
+ return false;
domain = __msi_create_irq_domain(fwnode, &bundle->info, IRQ_DOMAIN_FLAG_MSI_DEVICE, parent);
if (!domain)
- goto fail;
+ return false;
+ /* @bundle and @fwnode_alloced are now in use. Prevent cleanup */
+ retain_ptr(bundle);
+ retain_ptr(fwnode_alloced);
domain->dev = dev;
dev->msi.data->__domains[domid].domain = domain;
- msi_unlock_descs(dev);
return true;
-
-fail:
- msi_unlock_descs(dev);
-free_fwnode:
- irq_domain_free_fwnode(fwnalloced);
-free_bundle:
- kfree(bundle);
- return false;
}
/**
@@ -1074,12 +1064,10 @@ void msi_remove_device_irq_domain(struct
struct msi_domain_info *info;
struct irq_domain *domain;
- msi_lock_descs(dev);
-
+ guard(msi_descs_lock)(dev);
domain = msi_get_device_domain(dev, domid);
-
if (!domain || !irq_domain_is_msi_device(domain))
- goto unlock;
+ return;
dev->msi.data->__domains[domid].domain = NULL;
info = domain->host_data;
@@ -1088,9 +1076,6 @@ void msi_remove_device_irq_domain(struct
irq_domain_remove(domain);
irq_domain_free_fwnode(fwnode);
kfree(container_of(info, struct msi_domain_template, info));
-
-unlock:
- msi_unlock_descs(dev);
}
/**
@@ -1106,16 +1091,14 @@ bool msi_match_device_irq_domain(struct
{
struct msi_domain_info *info;
struct irq_domain *domain;
- bool ret = false;
- msi_lock_descs(dev);
+ guard(msi_descs_lock)(dev);
domain = msi_get_device_domain(dev, domid);
if (domain && irq_domain_is_msi_device(domain)) {
info = domain->host_data;
- ret = info->bus_token == bus_token;
+ return info->bus_token == bus_token;
}
- msi_unlock_descs(dev);
- return ret;
+ return false;
}
static int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
@@ -1365,12 +1348,9 @@ int msi_domain_alloc_irqs_range(struct d
.last = last,
.nirqs = last + 1 - first,
};
- int ret;
- msi_lock_descs(dev);
- ret = msi_domain_alloc_locked(dev, &ctrl);
- msi_unlock_descs(dev);
- return ret;
+ guard(msi_descs_lock)(dev);
+ return msi_domain_alloc_locked(dev, &ctrl);
}
EXPORT_SYMBOL_GPL(msi_domain_alloc_irqs_range);
@@ -1474,12 +1454,8 @@ struct msi_map msi_domain_alloc_irq_at(s
const struct irq_affinity_desc *affdesc,
union msi_instance_cookie *icookie)
{
- struct msi_map map;
-
- msi_lock_descs(dev);
- map = __msi_domain_alloc_irq_at(dev, domid, index, affdesc, icookie);
- msi_unlock_descs(dev);
- return map;
+ guard(msi_descs_lock)(dev);
+ return __msi_domain_alloc_irq_at(dev, domid, index, affdesc, icookie);
}
/**
@@ -1516,13 +1492,11 @@ int msi_device_domain_alloc_wired(struct
icookie.value = ((u64)type << 32) | hwirq;
- msi_lock_descs(dev);
+ guard(msi_descs_lock)(dev);
if (WARN_ON_ONCE(msi_get_device_domain(dev, domid) != domain))
map.index = -EINVAL;
else
map = __msi_domain_alloc_irq_at(dev, domid, MSI_ANY_INDEX, NULL, &icookie);
- msi_unlock_descs(dev);
-
return map.index >= 0 ? map.virq : map.index;
}
@@ -1615,9 +1589,8 @@ static void msi_domain_free_irqs_range_l
void msi_domain_free_irqs_range(struct device *dev, unsigned int domid,
unsigned int first, unsigned int last)
{
- msi_lock_descs(dev);
+ guard(msi_descs_lock)(dev);
msi_domain_free_irqs_range_locked(dev, domid, first, last);
- msi_unlock_descs(dev);
}
EXPORT_SYMBOL_GPL(msi_domain_free_irqs_all);
@@ -1647,9 +1620,8 @@ void msi_domain_free_irqs_all_locked(str
*/
void msi_domain_free_irqs_all(struct device *dev, unsigned int domid)
{
- msi_lock_descs(dev);
+ guard(msi_descs_lock)(dev);
msi_domain_free_irqs_all_locked(dev, domid);
- msi_unlock_descs(dev);
}
/**
@@ -1668,12 +1640,11 @@ void msi_device_domain_free_wired(struct
if (WARN_ON_ONCE(!dev || !desc || domain->bus_token != DOMAIN_BUS_WIRED_TO_MSI))
return;
- msi_lock_descs(dev);
- if (!WARN_ON_ONCE(msi_get_device_domain(dev, MSI_DEFAULT_DOMAIN) != domain)) {
- msi_domain_free_irqs_range_locked(dev, MSI_DEFAULT_DOMAIN, desc->msi_index,
- desc->msi_index);
- }
- msi_unlock_descs(dev);
+ guard(msi_descs_lock)(dev);
+ if (WARN_ON_ONCE(msi_get_device_domain(dev, MSI_DEFAULT_DOMAIN) != domain))
+ return;
+ msi_domain_free_irqs_range_locked(dev, MSI_DEFAULT_DOMAIN, desc->msi_index,
+ desc->msi_index);
}
/**
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 03/10] soc: ti: ti_sci_inta_msi: Switch MSI descriptor locking to guard()
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
2025-03-17 13:29 ` [patch V3 01/10] cleanup: Provide retain_ptr() Thomas Gleixner
2025-03-17 13:29 ` [patch V3 02/10] genirq/msi: Use lock guards for MSI descriptor locking Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-17 13:29 ` [patch V3 04/10] NTB/msi: Switch MSI descriptor locking to lock guard() Thomas Gleixner
` (6 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Nishanth Menon, Jonathan Cameron,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Bjorn Helgaas, linux-pci,
Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
linux-scsi, Jonathan Cameron
Convert the code to use the new guard(msi_descs_lock).
No functional change intended.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Nishanth Menon <nm@ti.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dhruva Gole <d-gole@ti.com>
Cc: Tero Kristo <kristo@kernel.org>
Cc: Santosh Shilimkar <ssantosh@kernel.org>
---
drivers/soc/ti/ti_sci_inta_msi.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
--- a/drivers/soc/ti/ti_sci_inta_msi.c
+++ b/drivers/soc/ti/ti_sci_inta_msi.c
@@ -103,19 +103,15 @@ int ti_sci_inta_msi_domain_alloc_irqs(st
if (ret)
return ret;
- msi_lock_descs(dev);
+ guard(msi_descs_lock)(dev);
nvec = ti_sci_inta_msi_alloc_descs(dev, res);
- if (nvec <= 0) {
- ret = nvec;
- goto unlock;
- }
+ if (nvec <= 0)
+ return nvec;
/* Use alloc ALL as it's unclear whether there are gaps in the indices */
ret = msi_domain_alloc_irqs_all_locked(dev, MSI_DEFAULT_DOMAIN, nvec);
if (ret)
dev_err(dev, "Failed to allocate IRQs %d\n", ret);
-unlock:
- msi_unlock_descs(dev);
return ret;
}
EXPORT_SYMBOL_GPL(ti_sci_inta_msi_domain_alloc_irqs);
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 04/10] NTB/msi: Switch MSI descriptor locking to lock guard()
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
` (2 preceding siblings ...)
2025-03-17 13:29 ` [patch V3 03/10] soc: ti: ti_sci_inta_msi: Switch MSI descriptor locking to guard() Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-17 13:29 ` [patch V3 05/10] PCI/MSI: Switch to MSI descriptor locking to guard() Thomas Gleixner
` (5 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Nishanth Menon,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Bjorn Helgaas,
linux-pci, Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv,
Wei Huang, Manivannan Sadhasivam, James E.J. Bottomley,
Martin K. Petersen, linux-scsi, Jonathan Cameron
Convert the code to use the new guard(msi_descs_lock).
No functional change intended.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
Acked-by: Dave Jiang <dave.jiang@intel.com>
Cc: Jon Mason <jdmason@kudzu.us>
Cc: Allen Hubbe <allenbh@gmail.com>
Cc: ntb@lists.linux.dev
---
drivers/ntb/msi.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
--- a/drivers/ntb/msi.c
+++ b/drivers/ntb/msi.c
@@ -106,10 +106,10 @@ int ntb_msi_setup_mws(struct ntb_dev *nt
if (!ntb->msi)
return -EINVAL;
- msi_lock_descs(&ntb->pdev->dev);
- desc = msi_first_desc(&ntb->pdev->dev, MSI_DESC_ASSOCIATED);
- addr = desc->msg.address_lo + ((uint64_t)desc->msg.address_hi << 32);
- msi_unlock_descs(&ntb->pdev->dev);
+ scoped_guard (msi_descs_lock, &ntb->pdev->dev) {
+ desc = msi_first_desc(&ntb->pdev->dev, MSI_DESC_ASSOCIATED);
+ addr = desc->msg.address_lo + ((uint64_t)desc->msg.address_hi << 32);
+ }
for (peer = 0; peer < ntb_peer_port_count(ntb); peer++) {
peer_widx = ntb_peer_highest_mw_idx(ntb, peer);
@@ -289,7 +289,7 @@ int ntbm_msi_request_threaded_irq(struct
if (!ntb->msi)
return -EINVAL;
- msi_lock_descs(dev);
+ guard(msi_descs_lock)(dev);
msi_for_each_desc(entry, dev, MSI_DESC_ASSOCIATED) {
if (irq_has_action(entry->irq))
continue;
@@ -307,17 +307,11 @@ int ntbm_msi_request_threaded_irq(struct
ret = ntbm_msi_setup_callback(ntb, entry, msi_desc);
if (ret) {
devm_free_irq(&ntb->dev, entry->irq, dev_id);
- goto unlock;
+ return ret;
}
-
- ret = entry->irq;
- goto unlock;
+ return entry->irq;
}
- ret = -ENODEV;
-
-unlock:
- msi_unlock_descs(dev);
- return ret;
+ return -ENODEV;
}
EXPORT_SYMBOL(ntbm_msi_request_threaded_irq);
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 05/10] PCI/MSI: Switch to MSI descriptor locking to guard()
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
` (3 preceding siblings ...)
2025-03-17 13:29 ` [patch V3 04/10] NTB/msi: Switch MSI descriptor locking to lock guard() Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-18 20:24 ` Bjorn Helgaas
2025-03-17 13:29 ` [patch V3 06/10] PCI: hv: Switch " Thomas Gleixner
` (4 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Bjorn Helgaas,
linux-pci, Nishanth Menon, Dhruva Gole, Tero Kristo,
Santosh Shilimkar, Logan Gunthorpe, Dave Jiang, Jon Mason,
Allen Hubbe, ntb, Michael Kelley, Wei Liu, Haiyang Zhang,
linux-hyperv, Wei Huang, Manivannan Sadhasivam,
James E.J. Bottomley, Martin K. Petersen, linux-scsi,
Jonathan Cameron
Convert the code to use the new guard(msi_descs_lock).
No functional change intended.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-pci@vger.kernel.org
---
V3: Use__free in __msix_setup_interrupts() - PeterZ
V2: Remove the gotos - Jonathan
---
drivers/pci/msi/api.c | 6 --
drivers/pci/msi/msi.c | 124 +++++++++++++++++++++++++-------------------------
2 files changed, 64 insertions(+), 66 deletions(-)
--- a/drivers/pci/msi/api.c
+++ b/drivers/pci/msi/api.c
@@ -53,10 +53,9 @@ void pci_disable_msi(struct pci_dev *dev
if (!pci_msi_enabled() || !dev || !dev->msi_enabled)
return;
- msi_lock_descs(&dev->dev);
+ guard(msi_descs_lock)(&dev->dev);
pci_msi_shutdown(dev);
pci_free_msi_irqs(dev);
- msi_unlock_descs(&dev->dev);
}
EXPORT_SYMBOL(pci_disable_msi);
@@ -196,10 +195,9 @@ void pci_disable_msix(struct pci_dev *de
if (!pci_msi_enabled() || !dev || !dev->msix_enabled)
return;
- msi_lock_descs(&dev->dev);
+ guard(msi_descs_lock)(&dev->dev);
pci_msix_shutdown(dev);
pci_free_msi_irqs(dev);
- msi_unlock_descs(&dev->dev);
}
EXPORT_SYMBOL(pci_disable_msix);
--- a/drivers/pci/msi/msi.c
+++ b/drivers/pci/msi/msi.c
@@ -336,41 +336,11 @@ static int msi_verify_entries(struct pci
return !entry ? 0 : -EIO;
}
-/**
- * msi_capability_init - configure device's MSI capability structure
- * @dev: pointer to the pci_dev data structure of MSI device function
- * @nvec: number of interrupts to allocate
- * @affd: description of automatic IRQ affinity assignments (may be %NULL)
- *
- * Setup the MSI capability structure of the device with the requested
- * number of interrupts. A return value of zero indicates the successful
- * setup of an entry with the new MSI IRQ. A negative return value indicates
- * an error, and a positive return value indicates the number of interrupts
- * which could have been allocated.
- */
-static int msi_capability_init(struct pci_dev *dev, int nvec,
- struct irq_affinity *affd)
+static int __msi_capability_init(struct pci_dev *dev, int nvec, struct irq_affinity_desc *masks)
{
- struct irq_affinity_desc *masks = NULL;
+ int ret = msi_setup_msi_desc(dev, nvec, masks);
struct msi_desc *entry, desc;
- int ret;
-
- /* Reject multi-MSI early on irq domain enabled architectures */
- if (nvec > 1 && !pci_msi_domain_supports(dev, MSI_FLAG_MULTI_PCI_MSI, ALLOW_LEGACY))
- return 1;
-
- /*
- * Disable MSI during setup in the hardware, but mark it enabled
- * so that setup code can evaluate it.
- */
- pci_msi_set_enable(dev, 0);
- dev->msi_enabled = 1;
-
- if (affd)
- masks = irq_create_affinity_masks(nvec, affd);
- msi_lock_descs(&dev->dev);
- ret = msi_setup_msi_desc(dev, nvec, masks);
if (ret)
goto fail;
@@ -399,19 +369,48 @@ static int msi_capability_init(struct pc
pcibios_free_irq(dev);
dev->irq = entry->irq;
- goto unlock;
-
+ return 0;
err:
pci_msi_unmask(&desc, msi_multi_mask(&desc));
pci_free_msi_irqs(dev);
fail:
dev->msi_enabled = 0;
-unlock:
- msi_unlock_descs(&dev->dev);
- kfree(masks);
return ret;
}
+/**
+ * msi_capability_init - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ * @nvec: number of interrupts to allocate
+ * @affd: description of automatic IRQ affinity assignments (may be %NULL)
+ *
+ * Setup the MSI capability structure of the device with the requested
+ * number of interrupts. A return value of zero indicates the successful
+ * setup of an entry with the new MSI IRQ. A negative return value indicates
+ * an error, and a positive return value indicates the number of interrupts
+ * which could have been allocated.
+ */
+static int msi_capability_init(struct pci_dev *dev, int nvec,
+ struct irq_affinity *affd)
+{
+ /* Reject multi-MSI early on irq domain enabled architectures */
+ if (nvec > 1 && !pci_msi_domain_supports(dev, MSI_FLAG_MULTI_PCI_MSI, ALLOW_LEGACY))
+ return 1;
+
+ /*
+ * Disable MSI during setup in the hardware, but mark it enabled
+ * so that setup code can evaluate it.
+ */
+ pci_msi_set_enable(dev, 0);
+ dev->msi_enabled = 1;
+
+ struct irq_affinity_desc *masks __free(kfree) =
+ affd ? irq_create_affinity_masks(nvec, affd) : NULL;
+
+ guard(msi_descs_lock)(&dev->dev);
+ return __msi_capability_init(dev, nvec, masks);
+}
+
int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
struct irq_affinity *affd)
{
@@ -666,38 +665,39 @@ static void msix_mask_all(void __iomem *
writel(ctrl, base + PCI_MSIX_ENTRY_VECTOR_CTRL);
}
-static int msix_setup_interrupts(struct pci_dev *dev, struct msix_entry *entries,
- int nvec, struct irq_affinity *affd)
-{
- struct irq_affinity_desc *masks = NULL;
- int ret;
+DEFINE_FREE(free_msi_irqs, struct pci_dev *, if (_T) pci_free_msi_irqs(_T));
- if (affd)
- masks = irq_create_affinity_masks(nvec, affd);
+static int __msix_setup_interrupts(struct pci_dev *__dev, struct msix_entry *entries,
+ int nvec, struct irq_affinity_desc *masks)
+{
+ struct pci_dev *dev __free(free_msi_irqs) = __dev;
- msi_lock_descs(&dev->dev);
- ret = msix_setup_msi_descs(dev, entries, nvec, masks);
+ int ret = msix_setup_msi_descs(dev, entries, nvec, masks);
if (ret)
- goto out_free;
+ return ret;
ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
if (ret)
- goto out_free;
+ return ret;
/* Check if all MSI entries honor device restrictions */
ret = msi_verify_entries(dev);
if (ret)
- goto out_free;
+ return ret;
+ retain_ptr(dev);
msix_update_entries(dev, entries);
- goto out_unlock;
+ return 0;
+}
-out_free:
- pci_free_msi_irqs(dev);
-out_unlock:
- msi_unlock_descs(&dev->dev);
- kfree(masks);
- return ret;
+static int msix_setup_interrupts(struct pci_dev *dev, struct msix_entry *entries,
+ int nvec, struct irq_affinity *affd)
+{
+ struct irq_affinity_desc *masks __free(kfree) =
+ affd ? irq_create_affinity_masks(nvec, affd) : NULL;
+
+ guard(msi_descs_lock)(&dev->dev);
+ return __msix_setup_interrupts(dev, entries, nvec, masks);
}
/**
@@ -871,13 +871,13 @@ void __pci_restore_msix_state(struct pci
write_msg = arch_restore_msi_irqs(dev);
- msi_lock_descs(&dev->dev);
- msi_for_each_desc(entry, &dev->dev, MSI_DESC_ALL) {
- if (write_msg)
- __pci_write_msi_msg(entry, &entry->msg);
- pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
+ scoped_guard (msi_descs_lock, &dev->dev) {
+ msi_for_each_desc(entry, &dev->dev, MSI_DESC_ALL) {
+ if (write_msg)
+ __pci_write_msi_msg(entry, &entry->msg);
+ pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
+ }
}
- msi_unlock_descs(&dev->dev);
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
}
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 06/10] PCI: hv: Switch MSI descriptor locking to guard()
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
` (4 preceding siblings ...)
2025-03-17 13:29 ` [patch V3 05/10] PCI/MSI: Switch to MSI descriptor locking to guard() Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-17 13:29 ` [patch V3 07/10] PCI/MSI: Provide a sane mechanism for TPH Thomas Gleixner
` (3 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Michael Kelley,
Wei Liu, Bjorn Helgaas, Haiyang Zhang, linux-hyperv, linux-pci,
Nishanth Menon, Dhruva Gole, Tero Kristo, Santosh Shilimkar,
Logan Gunthorpe, Dave Jiang, Jon Mason, Allen Hubbe, ntb,
Wei Huang, Manivannan Sadhasivam, James E.J. Bottomley,
Martin K. Petersen, linux-scsi, Jonathan Cameron
Convert the code to use the new guard(msi_descs_lock).
No functional change intended.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Acked-by: Wei Liu <wei.liu@kernel.org>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: linux-hyperv@vger.kernel.org
Cc: linux-pci@vger.kernel.org
---
drivers/pci/controller/pci-hyperv.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -3976,24 +3976,18 @@ static int hv_pci_restore_msi_msg(struct
{
struct irq_data *irq_data;
struct msi_desc *entry;
- int ret = 0;
if (!pdev->msi_enabled && !pdev->msix_enabled)
return 0;
- msi_lock_descs(&pdev->dev);
+ guard(msi_descs_lock)(&pdev->dev);
msi_for_each_desc(entry, &pdev->dev, MSI_DESC_ASSOCIATED) {
irq_data = irq_get_irq_data(entry->irq);
- if (WARN_ON_ONCE(!irq_data)) {
- ret = -EINVAL;
- break;
- }
-
+ if (WARN_ON_ONCE(!irq_data))
+ return -EINVAL;
hv_compose_msi_msg(irq_data, &entry->msg);
}
- msi_unlock_descs(&pdev->dev);
-
- return ret;
+ return 0;
}
/*
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 07/10] PCI/MSI: Provide a sane mechanism for TPH
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
` (5 preceding siblings ...)
2025-03-17 13:29 ` [patch V3 06/10] PCI: hv: Switch " Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-17 13:29 ` [patch V3 08/10] PCI/TPH: Replace the broken MSI-X control word update Thomas Gleixner
` (2 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Bjorn Helgaas, Wei Huang, linux-pci,
Jonathan Cameron, Nishanth Menon, Dhruva Gole, Tero Kristo,
Santosh Shilimkar, Logan Gunthorpe, Dave Jiang, Jon Mason,
Allen Hubbe, ntb, Michael Kelley, Wei Liu, Haiyang Zhang,
linux-hyperv, Manivannan Sadhasivam, James E.J. Bottomley,
Martin K. Petersen, linux-scsi, Jonathan Cameron
The PCI/TPH driver fiddles with the MSI-X control word of an active
interrupt completely unserialized against concurrent operations issued
from the interrupt core. It also brings the PCI/MSI-X internal cached
control word out of sync.
Provide a function, which has the required serialization and keeps the
control word cache in sync.
Unfortunately this requires to look up and lock the interrupt descriptor,
which should be only done in the interrupt core code. But confining this
particular oddity in the PCI/MSI core is the lesser of all evil. A
interrupt core implementation would require a larger pile of infrastructure
and indirections for dubious value.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Wei Huang <wei.huang2@amd.com>
Cc: linux-pci@vger.kernel.org
---
drivers/pci/msi/msi.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.h | 9 +++++++++
2 files changed, 56 insertions(+)
--- a/drivers/pci/msi/msi.c
+++ b/drivers/pci/msi/msi.c
@@ -910,6 +910,53 @@ void pci_free_msi_irqs(struct pci_dev *d
}
}
+#ifdef CONFIG_PCIE_TPH
+/**
+ * pci_msix_write_tph_tag - Update the TPH tag for a given MSI-X vector
+ * @pdev: The PCIe device to update
+ * @index: The MSI-X index to update
+ * @tag: The tag to write
+ *
+ * Returns: 0 on success, error code on failure
+ */
+int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int index, u16 tag)
+{
+ struct msi_desc *msi_desc;
+ struct irq_desc *irq_desc;
+ unsigned int virq;
+
+ if (!pdev->msix_enabled)
+ return -ENXIO;
+
+ guard(msi_descs_lock)(&pdev->dev);
+ virq = msi_get_virq(&pdev->dev, index);
+ if (!virq)
+ return -ENXIO;
+ /*
+ * This is a horrible hack, but short of implementing a PCI
+ * specific interrupt chip callback and a huge pile of
+ * infrastructure, this is the minor nuissance. It provides the
+ * protection against concurrent operations on this entry and keeps
+ * the control word cache in sync.
+ */
+ irq_desc = irq_to_desc(virq);
+ if (!irq_desc)
+ return -ENXIO;
+
+ guard(raw_spinlock_irq)(&irq_desc->lock);
+ msi_desc = irq_data_get_msi_desc(&irq_desc->irq_data);
+ if (!msi_desc || msi_desc->pci.msi_attrib.is_virtual)
+ return -ENXIO;
+
+ msi_desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_ST;
+ msi_desc->pci.msix_ctrl |= FIELD_PREP(PCI_MSIX_ENTRY_CTRL_ST, tag);
+ pci_msix_write_vector_ctrl(msi_desc, msi_desc->pci.msix_ctrl);
+ /* Flush the write */
+ readl(pci_msix_desc_addr(msi_desc));
+ return 0;
+}
+#endif
+
/* Misc. infrastructure */
struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -989,6 +989,15 @@ int pcim_request_region_exclusive(struct
const char *name);
void pcim_release_region(struct pci_dev *pdev, int bar);
+#ifdef CONFIG_PCI_MSI
+int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int index, u16 tag);
+#else
+static inline int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int index, u16 tag)
+{
+ return -ENODEV;
+}
+#endif
+
/*
* Config Address for PCI Configuration Mechanism #1
*
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 08/10] PCI/TPH: Replace the broken MSI-X control word update
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
` (6 preceding siblings ...)
2025-03-17 13:29 ` [patch V3 07/10] PCI/MSI: Provide a sane mechanism for TPH Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-17 13:29 ` [patch V3 09/10] scsi: ufs: qcom: Remove the MSI descriptor abuse Thomas Gleixner
2025-03-17 13:29 ` [patch V3 10/10] genirq/msi: Rename msi_[un]lock_descs() Thomas Gleixner
9 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Bjorn Helgaas, Wei Huang, linux-pci,
Jonathan Cameron, Nishanth Menon, Dhruva Gole, Tero Kristo,
Santosh Shilimkar, Logan Gunthorpe, Dave Jiang, Jon Mason,
Allen Hubbe, ntb, Michael Kelley, Wei Liu, Haiyang Zhang,
linux-hyperv, Manivannan Sadhasivam, James E.J. Bottomley,
Martin K. Petersen, linux-scsi, Jonathan Cameron
The driver walks the MSI descriptors to test whether a descriptor exists
for a given index. That's just abuse of the MSI internals.
The same test can be done with a single function call by looking up whether
there is a Linux interrupt number assigned at the index.
What's worse is that the function is completely unserialized against
modifications of the MSI-X control by operations issued from the interrupt
core. It also brings the PCI/MSI-X internal cached control word out of
sync.
Remove the trainwreck and invoke the function provided by the PCI/MSI core
to update it.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Wei Huang <wei.huang2@amd.com>
Cc: linux-pci@vger.kernel.org
---
drivers/pci/tph.c | 44 +-------------------------------------------
1 file changed, 1 insertion(+), 43 deletions(-)
--- a/drivers/pci/tph.c
+++ b/drivers/pci/tph.c
@@ -204,48 +204,6 @@ static u8 get_rp_completer_type(struct p
return FIELD_GET(PCI_EXP_DEVCAP2_TPH_COMP_MASK, reg);
}
-/* Write ST to MSI-X vector control reg - Return 0 if OK, otherwise -errno */
-static int write_tag_to_msix(struct pci_dev *pdev, int msix_idx, u16 tag)
-{
-#ifdef CONFIG_PCI_MSI
- struct msi_desc *msi_desc = NULL;
- void __iomem *vec_ctrl;
- u32 val;
- int err = 0;
-
- msi_lock_descs(&pdev->dev);
-
- /* Find the msi_desc entry with matching msix_idx */
- msi_for_each_desc(msi_desc, &pdev->dev, MSI_DESC_ASSOCIATED) {
- if (msi_desc->msi_index == msix_idx)
- break;
- }
-
- if (!msi_desc) {
- err = -ENXIO;
- goto err_out;
- }
-
- /* Get the vector control register (offset 0xc) pointed by msix_idx */
- vec_ctrl = pdev->msix_base + msix_idx * PCI_MSIX_ENTRY_SIZE;
- vec_ctrl += PCI_MSIX_ENTRY_VECTOR_CTRL;
-
- val = readl(vec_ctrl);
- val &= ~PCI_MSIX_ENTRY_CTRL_ST;
- val |= FIELD_PREP(PCI_MSIX_ENTRY_CTRL_ST, tag);
- writel(val, vec_ctrl);
-
- /* Read back to flush the update */
- val = readl(vec_ctrl);
-
-err_out:
- msi_unlock_descs(&pdev->dev);
- return err;
-#else
- return -ENODEV;
-#endif
-}
-
/* Write tag to ST table - Return 0 if OK, otherwise -errno */
static int write_tag_to_st_table(struct pci_dev *pdev, int index, u16 tag)
{
@@ -346,7 +304,7 @@ int pcie_tph_set_st_entry(struct pci_dev
switch (loc) {
case PCI_TPH_LOC_MSIX:
- err = write_tag_to_msix(pdev, index, tag);
+ err = pci_msix_write_tph_tag(pdev, index, tag);
break;
case PCI_TPH_LOC_CAP:
err = write_tag_to_st_table(pdev, index, tag);
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 09/10] scsi: ufs: qcom: Remove the MSI descriptor abuse
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
` (7 preceding siblings ...)
2025-03-17 13:29 ` [patch V3 08/10] PCI/TPH: Replace the broken MSI-X control word update Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
2025-03-17 16:26 ` James Bottomley
2025-03-17 13:29 ` [patch V3 10/10] genirq/msi: Rename msi_[un]lock_descs() Thomas Gleixner
9 siblings, 1 reply; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Manivannan Sadhasivam,
James E.J. Bottomley, Martin K. Petersen, linux-scsi,
Jonathan Cameron, Nishanth Menon, Dhruva Gole, Tero Kristo,
Santosh Shilimkar, Logan Gunthorpe, Dave Jiang, Jon Mason,
Allen Hubbe, ntb, Bjorn Helgaas, linux-pci, Michael Kelley,
Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang, Jonathan Cameron
The driver abuses the MSI descriptors for internal purposes. Aside of core
code and MSI providers nothing has to care about their existence. They have
been encapsulated with a lot of effort because this kind of abuse caused
all sorts of issues including a maintainability nightmare.
Rewrite the code so it uses dedicated storage to hand the required
information to the interrupt handler.
No functional change intended.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
---
drivers/ufs/host/ufs-qcom.c | 77 ++++++++++++++++++++++----------------------
1 file changed, 40 insertions(+), 37 deletions(-)
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -1782,15 +1782,19 @@ static void ufs_qcom_write_msi_msg(struc
ufshcd_mcq_config_esi(hba, msg);
}
+struct ufs_qcom_irq {
+ unsigned int irq;
+ unsigned int idx;
+ struct ufs_hba *hba;
+};
+
static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *data)
{
- struct msi_desc *desc = data;
- struct device *dev = msi_desc_to_dev(desc);
- struct ufs_hba *hba = dev_get_drvdata(dev);
- u32 id = desc->msi_index;
- struct ufs_hw_queue *hwq = &hba->uhq[id];
+ struct ufs_qcom_irq *qi = data;
+ struct ufs_hba *hba = qi->hba;
+ struct ufs_hw_queue *hwq = &hba->uhq[qi->idx];
- ufshcd_mcq_write_cqis(hba, 0x1, id);
+ ufshcd_mcq_write_cqis(hba, 0x1, qi->idx);
ufshcd_mcq_poll_cqe_lock(hba, hwq);
return IRQ_HANDLED;
@@ -1799,8 +1803,7 @@ static irqreturn_t ufs_qcom_mcq_esi_hand
static int ufs_qcom_config_esi(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct msi_desc *desc;
- struct msi_desc *failed_desc = NULL;
+ struct ufs_qcom_irq *qi;
int nr_irqs, ret;
if (host->esi_enabled)
@@ -1811,47 +1814,47 @@ static int ufs_qcom_config_esi(struct uf
* 2. Poll queues do not need ESI.
*/
nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
+ qi = devm_kcalloc(hba->dev, nr_irqs, sizeof(*qi), GFP_KERNEL);
+ if (qi)
+ return -ENOMEM;
+
ret = platform_device_msi_init_and_alloc_irqs(hba->dev, nr_irqs,
ufs_qcom_write_msi_msg);
if (ret) {
dev_err(hba->dev, "Failed to request Platform MSI %d\n", ret);
- return ret;
+ goto cleanup;
}
- msi_lock_descs(hba->dev);
- msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
- ret = devm_request_irq(hba->dev, desc->irq,
- ufs_qcom_mcq_esi_handler,
- IRQF_SHARED, "qcom-mcq-esi", desc);
+ for (int idx = 0; idx < nr_irqs; idx++) {
+ qi[idx].irq = msi_get_virq(hba->dev, idx);
+ qi[idx].idx = idx;
+ qi[idx].hba = hba;
+
+ ret = devm_request_irq(hba->dev, qi[idx].irq, ufs_qcom_mcq_esi_handler,
+ IRQF_SHARED, "qcom-mcq-esi", qi + idx);
if (ret) {
dev_err(hba->dev, "%s: Fail to request IRQ for %d, err = %d\n",
- __func__, desc->irq, ret);
- failed_desc = desc;
- break;
+ __func__, qi[idx].irq, ret);
+ qi[idx].irq = 0;
+ goto cleanup;
}
}
- msi_unlock_descs(hba->dev);
- if (ret) {
- /* Rewind */
- msi_lock_descs(hba->dev);
- msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
- if (desc == failed_desc)
- break;
- devm_free_irq(hba->dev, desc->irq, hba);
- }
- msi_unlock_descs(hba->dev);
- platform_device_msi_free_irqs_all(hba->dev);
- } else {
- if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
- host->hw_ver.step == 0)
- ufshcd_rmwl(hba, ESI_VEC_MASK,
- FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1),
- REG_UFS_CFG3);
- ufshcd_mcq_enable_esi(hba);
- host->esi_enabled = true;
+ if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
+ host->hw_ver.step == 0) {
+ ufshcd_rmwl(hba, ESI_VEC_MASK,
+ FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1),
+ REG_UFS_CFG3);
}
-
+ ufshcd_mcq_enable_esi(hba);
+ host->esi_enabled = true;
+ return 0;
+
+cleanup:
+ for (int idx = 0; qi[idx].irq; idx++)
+ devm_free_irq(hba->dev, qi[idx].irq, hba);
+ platform_device_msi_free_irqs_all(hba->dev);
+ devm_kfree(hba->dev, qi);
return ret;
}
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch V3 10/10] genirq/msi: Rename msi_[un]lock_descs()
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
` (8 preceding siblings ...)
2025-03-17 13:29 ` [patch V3 09/10] scsi: ufs: qcom: Remove the MSI descriptor abuse Thomas Gleixner
@ 2025-03-17 13:29 ` Thomas Gleixner
9 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-17 13:29 UTC (permalink / raw)
To: LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Jonathan Cameron,
Nishanth Menon, Dhruva Gole, Tero Kristo, Santosh Shilimkar,
Logan Gunthorpe, Dave Jiang, Jon Mason, Allen Hubbe, ntb,
Bjorn Helgaas, linux-pci, Michael Kelley, Wei Liu, Haiyang Zhang,
linux-hyperv, Wei Huang, Manivannan Sadhasivam,
James E.J. Bottomley, Martin K. Petersen, linux-scsi
Now that all abuse is gone and the legit users are converted to
guard(msi_descs_lock), rename the lock functions and document them as
internal.
No functional change.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huwei.com>
---
include/linux/msi.h | 8 ++++----
kernel/irq/msi.c | 16 ++++++++++------
2 files changed, 14 insertions(+), 10 deletions(-)
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -224,11 +224,11 @@ struct msi_dev_domain {
int msi_setup_device_data(struct device *dev);
-void msi_lock_descs(struct device *dev);
-void msi_unlock_descs(struct device *dev);
+void __msi_lock_descs(struct device *dev);
+void __msi_unlock_descs(struct device *dev);
-DEFINE_LOCK_GUARD_1(msi_descs_lock, struct device, msi_lock_descs(_T->lock),
- msi_unlock_descs(_T->lock));
+DEFINE_LOCK_GUARD_1(msi_descs_lock, struct device, __msi_lock_descs(_T->lock),
+ __msi_unlock_descs(_T->lock));
struct msi_desc *msi_domain_first_desc(struct device *dev, unsigned int domid,
enum msi_desc_filter filter);
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -337,26 +337,30 @@ int msi_setup_device_data(struct device
}
/**
- * msi_lock_descs - Lock the MSI descriptor storage of a device
+ * __msi_lock_descs - Lock the MSI descriptor storage of a device
* @dev: Device to operate on
+ *
+ * Internal function for guard(msi_descs_lock). Don't use in code.
*/
-void msi_lock_descs(struct device *dev)
+void __msi_lock_descs(struct device *dev)
{
mutex_lock(&dev->msi.data->mutex);
}
-EXPORT_SYMBOL_GPL(msi_lock_descs);
+EXPORT_SYMBOL_GPL(__msi_lock_descs);
/**
- * msi_unlock_descs - Unlock the MSI descriptor storage of a device
+ * __msi_unlock_descs - Unlock the MSI descriptor storage of a device
* @dev: Device to operate on
+ *
+ * Internal function for guard(msi_descs_lock). Don't use in code.
*/
-void msi_unlock_descs(struct device *dev)
+void __msi_unlock_descs(struct device *dev)
{
/* Invalidate the index which was cached by the iterator */
dev->msi.data->__iter_idx = MSI_XA_MAX_INDEX;
mutex_unlock(&dev->msi.data->mutex);
}
-EXPORT_SYMBOL_GPL(msi_unlock_descs);
+EXPORT_SYMBOL_GPL(__msi_unlock_descs);
static struct msi_desc *msi_find_desc(struct msi_device_data *md, unsigned int domid,
enum msi_desc_filter filter)
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch V3 01/10] cleanup: Provide retain_ptr()
2025-03-17 13:29 ` [patch V3 01/10] cleanup: Provide retain_ptr() Thomas Gleixner
@ 2025-03-17 13:57 ` James Bottomley
2025-03-18 8:37 ` Thomas Gleixner
0 siblings, 1 reply; 16+ messages in thread
From: James Bottomley @ 2025-03-17 13:57 UTC (permalink / raw)
To: Thomas Gleixner, LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Nishanth Menon,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Bjorn Helgaas, linux-pci,
Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang,
Manivannan Sadhasivam, Martin K. Petersen, linux-scsi,
Jonathan Cameron
On Mon, 2025-03-17 at 14:29 +0100, Thomas Gleixner wrote:
[...]
> +/*
> + * Only for situations where an allocation is handed in to another
> function
> + * and consumed by that function on success.
> + *
> + * struct foo *f __free(kfree) = kzalloc(sizeof(*f),
> GFP_KERNEL);
> + *
> + * setup(f);
> + * if (some_condition)
> + * return -EINVAL;
> + * ....
> + * ret = bar(f);
> + * if (!ret)
> + * retain_ptr(f);
> + * return ret;
> + */
> +#define retain_ptr(p) \
> + __get_and_null(p, NULL)
This doesn't score very highly on the Rusty API design scale because it
can be used anywhere return_ptr() should be used. To force the
distinction between the two cases at the compiler level, should there
be a cast to void in the above to prevent using the return value?
Regards,
James
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch V3 09/10] scsi: ufs: qcom: Remove the MSI descriptor abuse
2025-03-17 13:29 ` [patch V3 09/10] scsi: ufs: qcom: Remove the MSI descriptor abuse Thomas Gleixner
@ 2025-03-17 16:26 ` James Bottomley
2025-03-18 8:40 ` Thomas Gleixner
0 siblings, 1 reply; 16+ messages in thread
From: James Bottomley @ 2025-03-17 16:26 UTC (permalink / raw)
To: Thomas Gleixner, LKML
Cc: Marc Zyngier, Peter Zijlstra, Manivannan Sadhasivam,
Martin K. Petersen, linux-scsi, Jonathan Cameron, Nishanth Menon,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Bjorn Helgaas, linux-pci,
Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang,
Jonathan Cameron
On Mon, 2025-03-17 at 14:29 +0100, Thomas Gleixner wrote:
> The driver abuses the MSI descriptors for internal purposes. Aside of
> core code and MSI providers nothing has to care about their
> existence. They have been encapsulated with a lot of effort because
> this kind of abuse caused all sorts of issues including a
> maintainability nightmare.
>
> Rewrite the code so it uses dedicated storage to hand the required
> information to the interrupt handler.
>
> No functional change intended.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
> Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
> Cc: linux-scsi@vger.kernel.org
>
>
> ---
> drivers/ufs/host/ufs-qcom.c | 77 ++++++++++++++++++++++-----------
> -----------
> 1 file changed, 40 insertions(+), 37 deletions(-)
>
> --- a/drivers/ufs/host/ufs-qcom.c
> +++ b/drivers/ufs/host/ufs-qcom.c
> @@ -1782,15 +1782,19 @@ static void ufs_qcom_write_msi_msg(struc
> ufshcd_mcq_config_esi(hba, msg);
> }
>
> +struct ufs_qcom_irq {
> + unsigned int irq;
> + unsigned int idx;
> + struct ufs_hba *hba;
> +};
> +
> static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *data)
> {
> - struct msi_desc *desc = data;
> - struct device *dev = msi_desc_to_dev(desc);
> - struct ufs_hba *hba = dev_get_drvdata(dev);
> - u32 id = desc->msi_index;
> - struct ufs_hw_queue *hwq = &hba->uhq[id];
> + struct ufs_qcom_irq *qi = data;
> + struct ufs_hba *hba = qi->hba;
> + struct ufs_hw_queue *hwq = &hba->uhq[qi->idx];
>
> - ufshcd_mcq_write_cqis(hba, 0x1, id);
> + ufshcd_mcq_write_cqis(hba, 0x1, qi->idx);
> ufshcd_mcq_poll_cqe_lock(hba, hwq);
>
> return IRQ_HANDLED;
> @@ -1799,8 +1803,7 @@ static irqreturn_t ufs_qcom_mcq_esi_hand
> static int ufs_qcom_config_esi(struct ufs_hba *hba)
> {
> struct ufs_qcom_host *host = ufshcd_get_variant(hba);
> - struct msi_desc *desc;
> - struct msi_desc *failed_desc = NULL;
> + struct ufs_qcom_irq *qi;
> int nr_irqs, ret;
>
> if (host->esi_enabled)
> @@ -1811,47 +1814,47 @@ static int ufs_qcom_config_esi(struct uf
> * 2. Poll queues do not need ESI.
> */
> nr_irqs = hba->nr_hw_queues - hba-
> >nr_queues[HCTX_TYPE_POLL];
> + qi = devm_kcalloc(hba->dev, nr_irqs, sizeof(*qi),
> GFP_KERNEL);
> + if (qi)
Typo causing logic inversion: should be !qi here (you need a more
responsive ! key).
> + return -ENOMEM;
> +
> ret = platform_device_msi_init_and_alloc_irqs(hba->dev,
> nr_irqs,
>
> ufs_qcom_write_msi_msg);
> if (ret) {
> dev_err(hba->dev, "Failed to request Platform MSI
> %d\n", ret);
> - return ret;
> + goto cleanup;
> }
>
> - msi_lock_descs(hba->dev);
> - msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
> - ret = devm_request_irq(hba->dev, desc->irq,
> - ufs_qcom_mcq_esi_handler,
> - IRQF_SHARED, "qcom-mcq-esi",
> desc);
> + for (int idx = 0; idx < nr_irqs; idx++) {
> + qi[idx].irq = msi_get_virq(hba->dev, idx);
> + qi[idx].idx = idx;
> + qi[idx].hba = hba;
> +
> + ret = devm_request_irq(hba->dev, qi[idx].irq,
> ufs_qcom_mcq_esi_handler,
> + IRQF_SHARED, "qcom-mcq-esi",
> qi + idx);
> if (ret) {
> dev_err(hba->dev, "%s: Fail to request IRQ
> for %d, err = %d\n",
> - __func__, desc->irq, ret);
> - failed_desc = desc;
> - break;
> + __func__, qi[idx].irq, ret);
> + qi[idx].irq = 0;
> + goto cleanup;
> }
> }
> - msi_unlock_descs(hba->dev);
>
> - if (ret) {
> - /* Rewind */
> - msi_lock_descs(hba->dev);
> - msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
> - if (desc == failed_desc)
> - break;
> - devm_free_irq(hba->dev, desc->irq, hba);
> - }
> - msi_unlock_descs(hba->dev);
> - platform_device_msi_free_irqs_all(hba->dev);
> - } else {
> - if (host->hw_ver.major == 6 && host->hw_ver.minor ==
> 0 &&
> - host->hw_ver.step == 0)
> - ufshcd_rmwl(hba, ESI_VEC_MASK,
> - FIELD_PREP(ESI_VEC_MASK,
> MAX_ESI_VEC - 1),
> - REG_UFS_CFG3);
> - ufshcd_mcq_enable_esi(hba);
> - host->esi_enabled = true;
> + if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
> + host->hw_ver.step == 0) {
> + ufshcd_rmwl(hba, ESI_VEC_MASK,
> + FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC -
> 1),
> + REG_UFS_CFG3);
> }
> -
> + ufshcd_mcq_enable_esi(hba);
> + host->esi_enabled = true;
> + return 0;
> +
> +cleanup:
> + for (int idx = 0; qi[idx].irq; idx++)
> + devm_free_irq(hba->dev, qi[idx].irq, hba);
> + platform_device_msi_free_irqs_all(hba->dev);
> + devm_kfree(hba->dev, qi);
> return ret;
> }
This does seem to be exactly the pattern you describe in 1/10, although
I'm not entirely convinced that something like the below is more
readable and safe.
Regards,
James
---
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 23b9f6efa047..26b0c665c3b7 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -1782,25 +1782,37 @@ static void ufs_qcom_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
ufshcd_mcq_config_esi(hba, msg);
}
+struct ufs_qcom_irq {
+ unsigned int irq;
+ unsigned int idx;
+ struct ufs_hba *hba;
+};
+
static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *data)
{
- struct msi_desc *desc = data;
- struct device *dev = msi_desc_to_dev(desc);
- struct ufs_hba *hba = dev_get_drvdata(dev);
- u32 id = desc->msi_index;
- struct ufs_hw_queue *hwq = &hba->uhq[id];
+ struct ufs_qcom_irq *qi = data;
+ struct ufs_hba *hba = qi->hba;
+ struct ufs_hw_queue *hwq = &hba->uhq[qi->idx];
- ufshcd_mcq_write_cqis(hba, 0x1, id);
+ ufshcd_mcq_write_cqis(hba, 0x1, qi->idx);
ufshcd_mcq_poll_cqe_lock(hba, hwq);
return IRQ_HANDLED;
}
+DEFINE_FREE(ufs_qcom_irq, struct ufs_qcom_irq *,
+ if (_T) { \
+ for (int idx = 0; _T[idx].irq; idx++) \
+ devm_free_irq(_T[idx].hba->dev, _T[idx].irq, \
+ _T[idx].hba); \
+ platform_device_msi_free_irqs_all(_T[0].hba->dev); \
+ devm_kfree(_T[0].hba->dev, _T); \
+ })
+
static int ufs_qcom_config_esi(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct msi_desc *desc;
- struct msi_desc *failed_desc = NULL;
+ struct ufs_qcom_irq *qi __free(ufs_qcom_irq);
int nr_irqs, ret;
if (host->esi_enabled)
@@ -1811,6 +1823,11 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
* 2. Poll queues do not need ESI.
*/
nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
+ qi = devm_kcalloc(hba->dev, nr_irqs, sizeof(*qi), GFP_KERNEL);
+ if (!qi)
+ return -ENOMEM;
+ qi[0].hba = hba; /* required by __free() */
+
ret = platform_device_msi_init_and_alloc_irqs(hba->dev, nr_irqs,
ufs_qcom_write_msi_msg);
if (ret) {
@@ -1818,41 +1835,31 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
return ret;
}
- msi_lock_descs(hba->dev);
- msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
- ret = devm_request_irq(hba->dev, desc->irq,
- ufs_qcom_mcq_esi_handler,
- IRQF_SHARED, "qcom-mcq-esi", desc);
+ for (int idx = 0; idx < nr_irqs; idx++) {
+ qi[idx].irq = msi_get_virq(hba->dev, idx);
+ qi[idx].idx = idx;
+ qi[idx].hba = hba;
+
+ ret = devm_request_irq(hba->dev, qi[idx].irq, ufs_qcom_mcq_esi_handler,
+ IRQF_SHARED, "qcom-mcq-esi", qi + idx);
if (ret) {
dev_err(hba->dev, "%s: Fail to request IRQ for %d, err = %d\n",
- __func__, desc->irq, ret);
- failed_desc = desc;
- break;
+ __func__, qi[idx].irq, ret);
+ qi[idx].irq = 0;
+ return ret;
}
}
- msi_unlock_descs(hba->dev);
+ retain_ptr(qi);
- if (ret) {
- /* Rewind */
- msi_lock_descs(hba->dev);
- msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
- if (desc == failed_desc)
- break;
- devm_free_irq(hba->dev, desc->irq, hba);
- }
- msi_unlock_descs(hba->dev);
- platform_device_msi_free_irqs_all(hba->dev);
- } else {
- if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
- host->hw_ver.step == 0)
- ufshcd_rmwl(hba, ESI_VEC_MASK,
- FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1),
- REG_UFS_CFG3);
- ufshcd_mcq_enable_esi(hba);
- host->esi_enabled = true;
+ if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
+ host->hw_ver.step == 0) {
+ ufshcd_rmwl(hba, ESI_VEC_MASK,
+ FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1),
+ REG_UFS_CFG3);
}
-
- return ret;
+ ufshcd_mcq_enable_esi(hba);
+ host->esi_enabled = true;
+ return 0;
}
/*
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [patch V3 01/10] cleanup: Provide retain_ptr()
2025-03-17 13:57 ` James Bottomley
@ 2025-03-18 8:37 ` Thomas Gleixner
0 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-18 8:37 UTC (permalink / raw)
To: James Bottomley, LKML
Cc: Marc Zyngier, Peter Zijlstra, Jonathan Cameron, Nishanth Menon,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Bjorn Helgaas, linux-pci,
Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang,
Manivannan Sadhasivam, Martin K. Petersen, linux-scsi,
Jonathan Cameron
On Mon, Mar 17 2025 at 09:57, James Bottomley wrote:
> On Mon, 2025-03-17 at 14:29 +0100, Thomas Gleixner wrote:
>> +#define retain_ptr(p) \
>> + __get_and_null(p, NULL)
>
> This doesn't score very highly on the Rusty API design scale because it
> can be used anywhere return_ptr() should be used. To force the
> distinction between the two cases at the compiler level, should there
> be a cast to void in the above to prevent using the return value?
Indeed. Delta patch below seems to do the trick.
Thanks,
tglx
---
diff --git a/include/linux/cleanup.h b/include/linux/cleanup.h
index 6537f8dfe1bb..859b06d4ad7a 100644
--- a/include/linux/cleanup.h
+++ b/include/linux/cleanup.h
@@ -231,8 +231,7 @@ const volatile void * __must_check_fn(const volatile void *val)
* retain_ptr(f);
* return ret;
*/
-#define retain_ptr(p) \
- __get_and_null(p, NULL)
+#define retain_ptr(p) ((void)__get_and_null(p, NULL))
/*
* DEFINE_CLASS(name, type, exit, init, init_args...):
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [patch V3 09/10] scsi: ufs: qcom: Remove the MSI descriptor abuse
2025-03-17 16:26 ` James Bottomley
@ 2025-03-18 8:40 ` Thomas Gleixner
0 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2025-03-18 8:40 UTC (permalink / raw)
To: James Bottomley, LKML
Cc: Marc Zyngier, Peter Zijlstra, Manivannan Sadhasivam,
Martin K. Petersen, linux-scsi, Jonathan Cameron, Nishanth Menon,
Dhruva Gole, Tero Kristo, Santosh Shilimkar, Logan Gunthorpe,
Dave Jiang, Jon Mason, Allen Hubbe, ntb, Bjorn Helgaas, linux-pci,
Michael Kelley, Wei Liu, Haiyang Zhang, linux-hyperv, Wei Huang,
Jonathan Cameron
On Mon, Mar 17 2025 at 12:26, James Bottomley wrote:
>> nr_irqs = hba->nr_hw_queues - hba-
>> >nr_queues[HCTX_TYPE_POLL];
>> + qi = devm_kcalloc(hba->dev, nr_irqs, sizeof(*qi),
>> GFP_KERNEL);
>> + if (qi)
>
> Typo causing logic inversion: should be !qi here (you need a more
> responsive ! key).
Duh.
>> +cleanup:
>> + for (int idx = 0; qi[idx].irq; idx++)
>> + devm_free_irq(hba->dev, qi[idx].irq, hba);
>> + platform_device_msi_free_irqs_all(hba->dev);
>> + devm_kfree(hba->dev, qi);
>> return ret;
>> }
>
> This does seem to be exactly the pattern you describe in 1/10, although
True.
> I'm not entirely convinced that something like the below is more
> readable and safe.
At least the cleanup wants to be in a C function and not hideously
hidden in the DEFINE_FREE() macro.
Let me respin that.
Thanks,
tglx
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch V3 05/10] PCI/MSI: Switch to MSI descriptor locking to guard()
2025-03-17 13:29 ` [patch V3 05/10] PCI/MSI: Switch to MSI descriptor locking to guard() Thomas Gleixner
@ 2025-03-18 20:24 ` Bjorn Helgaas
0 siblings, 0 replies; 16+ messages in thread
From: Bjorn Helgaas @ 2025-03-18 20:24 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, Marc Zyngier, Peter Zijlstra, Jonathan Cameron,
Bjorn Helgaas, linux-pci, Nishanth Menon, Dhruva Gole,
Tero Kristo, Santosh Shilimkar, Logan Gunthorpe, Dave Jiang,
Jon Mason, Allen Hubbe, ntb, Michael Kelley, Wei Liu,
Haiyang Zhang, linux-hyperv, Wei Huang, Manivannan Sadhasivam,
James E.J. Bottomley, Martin K. Petersen, linux-scsi,
Jonathan Cameron
On Mon, Mar 17, 2025 at 02:29:27PM +0100, Thomas Gleixner wrote:
> Convert the code to use the new guard(msi_descs_lock).
>
> No functional change intended.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: linux-pci@vger.kernel.org
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
To help connect these together, I might mention "msi_descs_lock"
specifically in the subject line of the earlier patch:
genirq/msi: Use lock guards for MSI descriptor locking
The msi_capability_init() -> __msi_capability_init() rework is a big
chunk compared to the rest of this patch. Same for
msix_setup_interrupts() -> __msix_setup_interrupts().
I think I see the point (basically move the body to the new "__"
functions and put the guard() in the original functions before calling
the new ones).
> ---
> V3: Use__free in __msix_setup_interrupts() - PeterZ
> V2: Remove the gotos - Jonathan
> ---
> drivers/pci/msi/api.c | 6 --
> drivers/pci/msi/msi.c | 124 +++++++++++++++++++++++++-------------------------
> 2 files changed, 64 insertions(+), 66 deletions(-)
>
> --- a/drivers/pci/msi/api.c
> +++ b/drivers/pci/msi/api.c
> @@ -53,10 +53,9 @@ void pci_disable_msi(struct pci_dev *dev
> if (!pci_msi_enabled() || !dev || !dev->msi_enabled)
> return;
>
> - msi_lock_descs(&dev->dev);
> + guard(msi_descs_lock)(&dev->dev);
> pci_msi_shutdown(dev);
> pci_free_msi_irqs(dev);
> - msi_unlock_descs(&dev->dev);
> }
> EXPORT_SYMBOL(pci_disable_msi);
>
> @@ -196,10 +195,9 @@ void pci_disable_msix(struct pci_dev *de
> if (!pci_msi_enabled() || !dev || !dev->msix_enabled)
> return;
>
> - msi_lock_descs(&dev->dev);
> + guard(msi_descs_lock)(&dev->dev);
> pci_msix_shutdown(dev);
> pci_free_msi_irqs(dev);
> - msi_unlock_descs(&dev->dev);
> }
> EXPORT_SYMBOL(pci_disable_msix);
>
> --- a/drivers/pci/msi/msi.c
> +++ b/drivers/pci/msi/msi.c
> @@ -336,41 +336,11 @@ static int msi_verify_entries(struct pci
> return !entry ? 0 : -EIO;
> }
>
> -/**
> - * msi_capability_init - configure device's MSI capability structure
> - * @dev: pointer to the pci_dev data structure of MSI device function
> - * @nvec: number of interrupts to allocate
> - * @affd: description of automatic IRQ affinity assignments (may be %NULL)
> - *
> - * Setup the MSI capability structure of the device with the requested
> - * number of interrupts. A return value of zero indicates the successful
> - * setup of an entry with the new MSI IRQ. A negative return value indicates
> - * an error, and a positive return value indicates the number of interrupts
> - * which could have been allocated.
> - */
> -static int msi_capability_init(struct pci_dev *dev, int nvec,
> - struct irq_affinity *affd)
> +static int __msi_capability_init(struct pci_dev *dev, int nvec, struct irq_affinity_desc *masks)
> {
> - struct irq_affinity_desc *masks = NULL;
> + int ret = msi_setup_msi_desc(dev, nvec, masks);
> struct msi_desc *entry, desc;
> - int ret;
> -
> - /* Reject multi-MSI early on irq domain enabled architectures */
> - if (nvec > 1 && !pci_msi_domain_supports(dev, MSI_FLAG_MULTI_PCI_MSI, ALLOW_LEGACY))
> - return 1;
> -
> - /*
> - * Disable MSI during setup in the hardware, but mark it enabled
> - * so that setup code can evaluate it.
> - */
> - pci_msi_set_enable(dev, 0);
> - dev->msi_enabled = 1;
> -
> - if (affd)
> - masks = irq_create_affinity_masks(nvec, affd);
>
> - msi_lock_descs(&dev->dev);
> - ret = msi_setup_msi_desc(dev, nvec, masks);
> if (ret)
> goto fail;
>
> @@ -399,19 +369,48 @@ static int msi_capability_init(struct pc
>
> pcibios_free_irq(dev);
> dev->irq = entry->irq;
> - goto unlock;
> -
> + return 0;
> err:
> pci_msi_unmask(&desc, msi_multi_mask(&desc));
> pci_free_msi_irqs(dev);
> fail:
> dev->msi_enabled = 0;
> -unlock:
> - msi_unlock_descs(&dev->dev);
> - kfree(masks);
> return ret;
> }
>
> +/**
> + * msi_capability_init - configure device's MSI capability structure
> + * @dev: pointer to the pci_dev data structure of MSI device function
> + * @nvec: number of interrupts to allocate
> + * @affd: description of automatic IRQ affinity assignments (may be %NULL)
> + *
> + * Setup the MSI capability structure of the device with the requested
> + * number of interrupts. A return value of zero indicates the successful
> + * setup of an entry with the new MSI IRQ. A negative return value indicates
> + * an error, and a positive return value indicates the number of interrupts
> + * which could have been allocated.
> + */
> +static int msi_capability_init(struct pci_dev *dev, int nvec,
> + struct irq_affinity *affd)
> +{
> + /* Reject multi-MSI early on irq domain enabled architectures */
> + if (nvec > 1 && !pci_msi_domain_supports(dev, MSI_FLAG_MULTI_PCI_MSI, ALLOW_LEGACY))
> + return 1;
> +
> + /*
> + * Disable MSI during setup in the hardware, but mark it enabled
> + * so that setup code can evaluate it.
> + */
> + pci_msi_set_enable(dev, 0);
> + dev->msi_enabled = 1;
> +
> + struct irq_affinity_desc *masks __free(kfree) =
> + affd ? irq_create_affinity_masks(nvec, affd) : NULL;
> +
> + guard(msi_descs_lock)(&dev->dev);
> + return __msi_capability_init(dev, nvec, masks);
> +}
> +
> int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
> struct irq_affinity *affd)
> {
> @@ -666,38 +665,39 @@ static void msix_mask_all(void __iomem *
> writel(ctrl, base + PCI_MSIX_ENTRY_VECTOR_CTRL);
> }
>
> -static int msix_setup_interrupts(struct pci_dev *dev, struct msix_entry *entries,
> - int nvec, struct irq_affinity *affd)
> -{
> - struct irq_affinity_desc *masks = NULL;
> - int ret;
> +DEFINE_FREE(free_msi_irqs, struct pci_dev *, if (_T) pci_free_msi_irqs(_T));
>
> - if (affd)
> - masks = irq_create_affinity_masks(nvec, affd);
> +static int __msix_setup_interrupts(struct pci_dev *__dev, struct msix_entry *entries,
> + int nvec, struct irq_affinity_desc *masks)
> +{
> + struct pci_dev *dev __free(free_msi_irqs) = __dev;
>
> - msi_lock_descs(&dev->dev);
> - ret = msix_setup_msi_descs(dev, entries, nvec, masks);
> + int ret = msix_setup_msi_descs(dev, entries, nvec, masks);
> if (ret)
> - goto out_free;
> + return ret;
>
> ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
> if (ret)
> - goto out_free;
> + return ret;
>
> /* Check if all MSI entries honor device restrictions */
> ret = msi_verify_entries(dev);
> if (ret)
> - goto out_free;
> + return ret;
>
> + retain_ptr(dev);
> msix_update_entries(dev, entries);
> - goto out_unlock;
> + return 0;
> +}
>
> -out_free:
> - pci_free_msi_irqs(dev);
> -out_unlock:
> - msi_unlock_descs(&dev->dev);
> - kfree(masks);
> - return ret;
> +static int msix_setup_interrupts(struct pci_dev *dev, struct msix_entry *entries,
> + int nvec, struct irq_affinity *affd)
> +{
> + struct irq_affinity_desc *masks __free(kfree) =
> + affd ? irq_create_affinity_masks(nvec, affd) : NULL;
> +
> + guard(msi_descs_lock)(&dev->dev);
> + return __msix_setup_interrupts(dev, entries, nvec, masks);
> }
>
> /**
> @@ -871,13 +871,13 @@ void __pci_restore_msix_state(struct pci
>
> write_msg = arch_restore_msi_irqs(dev);
>
> - msi_lock_descs(&dev->dev);
> - msi_for_each_desc(entry, &dev->dev, MSI_DESC_ALL) {
> - if (write_msg)
> - __pci_write_msi_msg(entry, &entry->msg);
> - pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
> + scoped_guard (msi_descs_lock, &dev->dev) {
> + msi_for_each_desc(entry, &dev->dev, MSI_DESC_ALL) {
> + if (write_msg)
> + __pci_write_msi_msg(entry, &entry->msg);
> + pci_msix_write_vector_ctrl(entry, entry->pci.msix_ctrl);
> + }
> }
> - msi_unlock_descs(&dev->dev);
>
> pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
> }
>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2025-03-18 20:24 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-17 13:29 [patch V3 00/10] genirq/msi: Spring cleaning Thomas Gleixner
2025-03-17 13:29 ` [patch V3 01/10] cleanup: Provide retain_ptr() Thomas Gleixner
2025-03-17 13:57 ` James Bottomley
2025-03-18 8:37 ` Thomas Gleixner
2025-03-17 13:29 ` [patch V3 02/10] genirq/msi: Use lock guards for MSI descriptor locking Thomas Gleixner
2025-03-17 13:29 ` [patch V3 03/10] soc: ti: ti_sci_inta_msi: Switch MSI descriptor locking to guard() Thomas Gleixner
2025-03-17 13:29 ` [patch V3 04/10] NTB/msi: Switch MSI descriptor locking to lock guard() Thomas Gleixner
2025-03-17 13:29 ` [patch V3 05/10] PCI/MSI: Switch to MSI descriptor locking to guard() Thomas Gleixner
2025-03-18 20:24 ` Bjorn Helgaas
2025-03-17 13:29 ` [patch V3 06/10] PCI: hv: Switch " Thomas Gleixner
2025-03-17 13:29 ` [patch V3 07/10] PCI/MSI: Provide a sane mechanism for TPH Thomas Gleixner
2025-03-17 13:29 ` [patch V3 08/10] PCI/TPH: Replace the broken MSI-X control word update Thomas Gleixner
2025-03-17 13:29 ` [patch V3 09/10] scsi: ufs: qcom: Remove the MSI descriptor abuse Thomas Gleixner
2025-03-17 16:26 ` James Bottomley
2025-03-18 8:40 ` Thomas Gleixner
2025-03-17 13:29 ` [patch V3 10/10] genirq/msi: Rename msi_[un]lock_descs() Thomas Gleixner
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).