Commit 89033762 authored by Thomas Gleixner's avatar Thomas Gleixner

genirq/msi: Handle PCI/MSI allocation fail in core code

Get rid of yet another irqdomain callback and let the core code return the
already available information of how many descriptors could be allocated.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Tested-by: default avatarJuergen Gross <jgross@suse.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>	# PCI
Link: https://lore.kernel.org/r/20211206210225.046615302@linutronix.de
parent 57ce3a3c
...@@ -95,16 +95,6 @@ static int pci_msi_domain_check_cap(struct irq_domain *domain, ...@@ -95,16 +95,6 @@ static int pci_msi_domain_check_cap(struct irq_domain *domain,
return 0; return 0;
} }
static int pci_msi_domain_handle_error(struct irq_domain *domain,
struct msi_desc *desc, int error)
{
/* Special handling to support __pci_enable_msi_range() */
if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
return 1;
return error;
}
static void pci_msi_domain_set_desc(msi_alloc_info_t *arg, static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
struct msi_desc *desc) struct msi_desc *desc)
{ {
...@@ -115,7 +105,6 @@ static void pci_msi_domain_set_desc(msi_alloc_info_t *arg, ...@@ -115,7 +105,6 @@ static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
static struct msi_domain_ops pci_msi_domain_ops_default = { static struct msi_domain_ops pci_msi_domain_ops_default = {
.set_desc = pci_msi_domain_set_desc, .set_desc = pci_msi_domain_set_desc,
.msi_check = pci_msi_domain_check_cap, .msi_check = pci_msi_domain_check_cap,
.handle_error = pci_msi_domain_handle_error,
}; };
static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info) static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
...@@ -129,8 +118,6 @@ static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info) ...@@ -129,8 +118,6 @@ static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
ops->set_desc = pci_msi_domain_set_desc; ops->set_desc = pci_msi_domain_set_desc;
if (ops->msi_check == NULL) if (ops->msi_check == NULL)
ops->msi_check = pci_msi_domain_check_cap; ops->msi_check = pci_msi_domain_check_cap;
if (ops->handle_error == NULL)
ops->handle_error = pci_msi_domain_handle_error;
} }
} }
......
...@@ -286,7 +286,6 @@ struct msi_domain_info; ...@@ -286,7 +286,6 @@ struct msi_domain_info;
* @msi_check: Callback for verification of the domain/info/dev data * @msi_check: Callback for verification of the domain/info/dev data
* @msi_prepare: Prepare the allocation of the interrupts in the domain * @msi_prepare: Prepare the allocation of the interrupts in the domain
* @set_desc: Set the msi descriptor for an interrupt * @set_desc: Set the msi descriptor for an interrupt
* @handle_error: Optional error handler if the allocation fails
* @domain_alloc_irqs: Optional function to override the default allocation * @domain_alloc_irqs: Optional function to override the default allocation
* function. * function.
* @domain_free_irqs: Optional function to override the default free * @domain_free_irqs: Optional function to override the default free
...@@ -295,7 +294,7 @@ struct msi_domain_info; ...@@ -295,7 +294,7 @@ struct msi_domain_info;
* @get_hwirq, @msi_init and @msi_free are callbacks used by the underlying * @get_hwirq, @msi_init and @msi_free are callbacks used by the underlying
* irqdomain. * irqdomain.
* *
* @msi_check, @msi_prepare, @handle_error and @set_desc are callbacks used by * @msi_check, @msi_prepare and @set_desc are callbacks used by
* msi_domain_alloc/free_irqs(). * msi_domain_alloc/free_irqs().
* *
* @domain_alloc_irqs, @domain_free_irqs can be used to override the * @domain_alloc_irqs, @domain_free_irqs can be used to override the
...@@ -332,8 +331,6 @@ struct msi_domain_ops { ...@@ -332,8 +331,6 @@ struct msi_domain_ops {
msi_alloc_info_t *arg); msi_alloc_info_t *arg);
void (*set_desc)(msi_alloc_info_t *arg, void (*set_desc)(msi_alloc_info_t *arg,
struct msi_desc *desc); struct msi_desc *desc);
int (*handle_error)(struct irq_domain *domain,
struct msi_desc *desc, int error);
int (*domain_alloc_irqs)(struct irq_domain *domain, int (*domain_alloc_irqs)(struct irq_domain *domain,
struct device *dev, int nvec); struct device *dev, int nvec);
void (*domain_free_irqs)(struct irq_domain *domain, void (*domain_free_irqs)(struct irq_domain *domain,
......
...@@ -538,6 +538,27 @@ static bool msi_check_reservation_mode(struct irq_domain *domain, ...@@ -538,6 +538,27 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
return desc->pci.msi_attrib.is_msix || desc->pci.msi_attrib.can_mask; return desc->pci.msi_attrib.is_msix || desc->pci.msi_attrib.can_mask;
} }
static int msi_handle_pci_fail(struct irq_domain *domain, struct msi_desc *desc,
int allocated)
{
switch(domain->bus_token) {
case DOMAIN_BUS_PCI_MSI:
case DOMAIN_BUS_VMD_MSI:
if (IS_ENABLED(CONFIG_PCI_MSI))
break;
fallthrough;
default:
return -ENOSPC;
}
/* Let a failed PCI multi MSI allocation retry */
if (desc->nvec_used > 1)
return 1;
/* If there was a successful allocation let the caller know */
return allocated ? allocated : -ENOSPC;
}
int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
int nvec) int nvec)
{ {
...@@ -546,6 +567,7 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, ...@@ -546,6 +567,7 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
struct irq_data *irq_data; struct irq_data *irq_data;
struct msi_desc *desc; struct msi_desc *desc;
msi_alloc_info_t arg = { }; msi_alloc_info_t arg = { };
int allocated = 0;
int i, ret, virq; int i, ret, virq;
bool can_reserve; bool can_reserve;
...@@ -560,16 +582,15 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, ...@@ -560,16 +582,15 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
dev_to_node(dev), &arg, false, dev_to_node(dev), &arg, false,
desc->affinity); desc->affinity);
if (virq < 0) { if (virq < 0) {
ret = -ENOSPC; ret = msi_handle_pci_fail(domain, desc, allocated);
if (ops->handle_error) goto cleanup;
ret = ops->handle_error(domain, desc, ret);
return ret;
} }
for (i = 0; i < desc->nvec_used; i++) { for (i = 0; i < desc->nvec_used; i++) {
irq_set_msi_desc_off(virq, i, desc); irq_set_msi_desc_off(virq, i, desc);
irq_debugfs_copy_devname(virq + i, dev); irq_debugfs_copy_devname(virq + i, dev);
} }
allocated++;
} }
can_reserve = msi_check_reservation_mode(domain, info, dev); can_reserve = msi_check_reservation_mode(domain, info, dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment