|
@@ -14,7 +14,6 @@
|
|
*/
|
|
*/
|
|
#include <linux/irq.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/bootmem.h>
|
|
#include <linux/bootmem.h>
|
|
-#include <linux/bitmap.h>
|
|
|
|
#include <linux/msi.h>
|
|
#include <linux/msi.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/of_platform.h>
|
|
@@ -67,96 +66,22 @@ static struct irq_host_ops fsl_msi_host_ops = {
|
|
.map = fsl_msi_host_map,
|
|
.map = fsl_msi_host_map,
|
|
};
|
|
};
|
|
|
|
|
|
-static irq_hw_number_t fsl_msi_alloc_hwirqs(struct fsl_msi *msi, int num)
|
|
|
|
-{
|
|
|
|
- unsigned long flags;
|
|
|
|
- int order = get_count_order(num);
|
|
|
|
- int offset;
|
|
|
|
-
|
|
|
|
- spin_lock_irqsave(&msi->bitmap_lock, flags);
|
|
|
|
-
|
|
|
|
- offset = bitmap_find_free_region(msi->fsl_msi_bitmap,
|
|
|
|
- NR_MSI_IRQS, order);
|
|
|
|
-
|
|
|
|
- spin_unlock_irqrestore(&msi->bitmap_lock, flags);
|
|
|
|
-
|
|
|
|
- pr_debug("%s: allocated 0x%x (2^%d) at offset 0x%x\n",
|
|
|
|
- __func__, num, order, offset);
|
|
|
|
-
|
|
|
|
- return offset;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void fsl_msi_free_hwirqs(struct fsl_msi *msi, int offset, int num)
|
|
|
|
-{
|
|
|
|
- unsigned long flags;
|
|
|
|
- int order = get_count_order(num);
|
|
|
|
-
|
|
|
|
- pr_debug("%s: freeing 0x%x (2^%d) at offset 0x%x\n",
|
|
|
|
- __func__, num, order, offset);
|
|
|
|
-
|
|
|
|
- spin_lock_irqsave(&msi->bitmap_lock, flags);
|
|
|
|
- bitmap_release_region(msi->fsl_msi_bitmap, offset, order);
|
|
|
|
- spin_unlock_irqrestore(&msi->bitmap_lock, flags);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int fsl_msi_free_dt_hwirqs(struct fsl_msi *msi)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- int len;
|
|
|
|
- const u32 *p;
|
|
|
|
-
|
|
|
|
- bitmap_allocate_region(msi->fsl_msi_bitmap, 0,
|
|
|
|
- get_count_order(NR_MSI_IRQS));
|
|
|
|
-
|
|
|
|
- p = of_get_property(msi->irqhost->of_node, "msi-available-ranges",
|
|
|
|
- &len);
|
|
|
|
-
|
|
|
|
- if (!p) {
|
|
|
|
- /* No msi-available-ranges property,
|
|
|
|
- * All the 256 MSI interrupts can be used
|
|
|
|
- */
|
|
|
|
- fsl_msi_free_hwirqs(msi, 0, 0x100);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ((len % (2 * sizeof(u32))) != 0) {
|
|
|
|
- printk(KERN_WARNING "fsl_msi: Malformed msi-available-ranges "
|
|
|
|
- "property on %s\n", msi->irqhost->of_node->full_name);
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Format is: (<u32 start> <u32 count>)+ */
|
|
|
|
- len /= 2 * sizeof(u32);
|
|
|
|
- for (i = 0; i < len; i++, p += 2)
|
|
|
|
- fsl_msi_free_hwirqs(msi, *p, *(p + 1));
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
|
|
static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
|
|
{
|
|
{
|
|
int rc;
|
|
int rc;
|
|
- int size = BITS_TO_LONGS(NR_MSI_IRQS) * sizeof(u32);
|
|
|
|
|
|
|
|
- msi_data->fsl_msi_bitmap = kzalloc(size, GFP_KERNEL);
|
|
|
|
|
|
+ rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
|
|
|
|
+ msi_data->irqhost->of_node);
|
|
|
|
+ if (rc)
|
|
|
|
+ return rc;
|
|
|
|
|
|
- if (msi_data->fsl_msi_bitmap == NULL) {
|
|
|
|
- pr_debug("%s: ENOMEM allocating allocator bitmap!\n",
|
|
|
|
- __func__);
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ msi_bitmap_free(&msi_data->bitmap);
|
|
|
|
+ return rc;
|
|
}
|
|
}
|
|
|
|
|
|
- rc = fsl_msi_free_dt_hwirqs(msi_data);
|
|
|
|
- if (rc)
|
|
|
|
- goto out_free;
|
|
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
-out_free:
|
|
|
|
- kfree(msi_data->fsl_msi_bitmap);
|
|
|
|
-
|
|
|
|
- msi_data->fsl_msi_bitmap = NULL;
|
|
|
|
- return rc;
|
|
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
|
|
static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
|
|
@@ -176,7 +101,8 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
|
|
if (entry->irq == NO_IRQ)
|
|
if (entry->irq == NO_IRQ)
|
|
continue;
|
|
continue;
|
|
set_irq_msi(entry->irq, NULL);
|
|
set_irq_msi(entry->irq, NULL);
|
|
- fsl_msi_free_hwirqs(msi_data, virq_to_hw(entry->irq), 1);
|
|
|
|
|
|
+ msi_bitmap_free_hwirqs(&msi_data->bitmap,
|
|
|
|
+ virq_to_hw(entry->irq), 1);
|
|
irq_dispose_mapping(entry->irq);
|
|
irq_dispose_mapping(entry->irq);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -198,15 +124,14 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
|
|
|
|
|
|
static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
|
|
static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
|
|
{
|
|
{
|
|
- irq_hw_number_t hwirq;
|
|
|
|
- int rc;
|
|
|
|
|
|
+ int rc, hwirq;
|
|
unsigned int virq;
|
|
unsigned int virq;
|
|
struct msi_desc *entry;
|
|
struct msi_desc *entry;
|
|
struct msi_msg msg;
|
|
struct msi_msg msg;
|
|
struct fsl_msi *msi_data = fsl_msi;
|
|
struct fsl_msi *msi_data = fsl_msi;
|
|
|
|
|
|
list_for_each_entry(entry, &pdev->msi_list, list) {
|
|
list_for_each_entry(entry, &pdev->msi_list, list) {
|
|
- hwirq = fsl_msi_alloc_hwirqs(msi_data, 1);
|
|
|
|
|
|
+ hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
|
|
if (hwirq < 0) {
|
|
if (hwirq < 0) {
|
|
rc = hwirq;
|
|
rc = hwirq;
|
|
pr_debug("%s: fail allocating msi interrupt\n",
|
|
pr_debug("%s: fail allocating msi interrupt\n",
|
|
@@ -217,9 +142,9 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
|
|
virq = irq_create_mapping(msi_data->irqhost, hwirq);
|
|
virq = irq_create_mapping(msi_data->irqhost, hwirq);
|
|
|
|
|
|
if (virq == NO_IRQ) {
|
|
if (virq == NO_IRQ) {
|
|
- pr_debug("%s: fail mapping hwirq 0x%lx\n",
|
|
|
|
|
|
+ pr_debug("%s: fail mapping hwirq 0x%x\n",
|
|
__func__, hwirq);
|
|
__func__, hwirq);
|
|
- fsl_msi_free_hwirqs(msi_data, hwirq, 1);
|
|
|
|
|
|
+ msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
|
|
rc = -ENOSPC;
|
|
rc = -ENOSPC;
|
|
goto out_free;
|
|
goto out_free;
|
|
}
|
|
}
|