lkml.org 
[lkml]   [2022]   [Jul]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V15 10/15] irqchip/loongson-htvec: Add ACPI init support
    Date
    From: Huacai Chen <chenhuacai@loongson.cn>

    HTVECINTC stands for "HyperTransport Interrupts" that described in
    Section 14.3 of "Loongson 3A5000 Processor Reference Manual". For more
    information please refer Documentation/loongarch/irq-chip-model.rst.

    Co-developed-by: Jianmin Lv <lvjianmin@loongson.cn>
    Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn>
    Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
    ---
    arch/loongarch/include/asm/irq.h | 2 +-
    drivers/irqchip/irq-loongson-htvec.c | 145 +++++++++++++++++++++++++++--------
    2 files changed, 112 insertions(+), 35 deletions(-)

    diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
    index 6022406..8775dc6 100644
    --- a/arch/loongarch/include/asm/irq.h
    +++ b/arch/loongarch/include/asm/irq.h
    @@ -102,7 +102,7 @@ struct irq_domain *liointc_acpi_init(struct irq_domain *parent,
    struct irq_domain *eiointc_acpi_init(struct irq_domain *parent,
    struct acpi_madt_eio_pic *acpi_eiointc);

    -struct irq_domain *htvec_acpi_init(struct irq_domain *parent,
    +int htvec_acpi_init(struct irq_domain *parent,
    struct acpi_madt_ht_pic *acpi_htvec);
    int pch_lpc_acpi_init(struct irq_domain *parent,
    struct acpi_madt_lpc_pic *acpi_pchlpc);
    diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c
    index 60a335d..65f4938 100644
    --- a/drivers/irqchip/irq-loongson-htvec.c
    +++ b/drivers/irqchip/irq-loongson-htvec.c
    @@ -20,7 +20,6 @@
    /* Registers */
    #define HTVEC_EN_OFF 0x20
    #define HTVEC_MAX_PARENT_IRQ 8
    -
    #define VEC_COUNT_PER_REG 32
    #define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG)
    #define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG)
    @@ -32,6 +31,8 @@ struct htvec {
    raw_spinlock_t htvec_lock;
    };

    +static struct htvec *htvec_priv;
    +
    static void htvec_irq_dispatch(struct irq_desc *desc)
    {
    int i;
    @@ -155,64 +156,140 @@ static void htvec_reset(struct htvec *priv)
    }
    }

    -static int htvec_of_init(struct device_node *node,
    - struct device_node *parent)
    +static int htvec_init(phys_addr_t addr, unsigned long size,
    + int num_parents, int parent_irq[], struct fwnode_handle *domain_handle)
    {
    + int i;
    struct htvec *priv;
    - int err, parent_irq[8], i;

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    if (!priv)
    return -ENOMEM;

    + priv->num_parents = num_parents;
    + priv->base = ioremap(addr, size);
    raw_spin_lock_init(&priv->htvec_lock);
    - priv->base = of_iomap(node, 0);
    - if (!priv->base) {
    - err = -ENOMEM;
    - goto free_priv;
    - }
    -
    - /* Interrupt may come from any of the 8 interrupt lines */
    - for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
    - parent_irq[i] = irq_of_parse_and_map(node, i);
    - if (parent_irq[i] <= 0)
    - break;
    -
    - priv->num_parents++;
    - }
    -
    - if (!priv->num_parents) {
    - pr_err("Failed to get parent irqs\n");
    - err = -ENODEV;
    - goto iounmap_base;
    - }

    - priv->htvec_domain = irq_domain_create_linear(of_node_to_fwnode(node),
    + /* Setup IRQ domain */
    + priv->htvec_domain = irq_domain_create_linear(domain_handle,
    (VEC_COUNT_PER_REG * priv->num_parents),
    &htvec_domain_ops, priv);
    if (!priv->htvec_domain) {
    - pr_err("Failed to create IRQ domain\n");
    - err = -ENOMEM;
    - goto irq_dispose;
    + pr_err("loongson-htvec: cannot add IRQ domain\n");
    + goto iounmap_base;
    }

    htvec_reset(priv);

    - for (i = 0; i < priv->num_parents; i++)
    + for (i = 0; i < priv->num_parents; i++) {
    irq_set_chained_handler_and_data(parent_irq[i],
    htvec_irq_dispatch, priv);
    + }
    +
    + htvec_priv = priv;

    return 0;

    -irq_dispose:
    - for (; i > 0; i--)
    - irq_dispose_mapping(parent_irq[i - 1]);
    iounmap_base:
    iounmap(priv->base);
    -free_priv:
    kfree(priv);

    - return err;
    + return -EINVAL;
    +}
    +
    +#ifdef CONFIG_OF
    +
    +static int htvec_of_init(struct device_node *node,
    + struct device_node *parent)
    +{
    + int i, err;
    + int parent_irq[8];
    + int num_parents = 0;
    + struct resource res;
    +
    + if (of_address_to_resource(node, 0, &res))
    + return -EINVAL;
    +
    + /* Interrupt may come from any of the 8 interrupt lines */
    + for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) {
    + parent_irq[i] = irq_of_parse_and_map(node, i);
    + if (parent_irq[i] <= 0)
    + break;
    +
    + num_parents++;
    + }
    +
    + err = htvec_init(res.start, resource_size(&res),
    + num_parents, parent_irq, of_node_to_fwnode(node));
    + if (err < 0)
    + return err;
    +
    + return 0;
    }

    IRQCHIP_DECLARE(htvec, "loongson,htvec-1.0", htvec_of_init);
    +
    +#endif
    +
    +#ifdef CONFIG_ACPI
    +static int __init
    +pch_pic_parse_madt(union acpi_subtable_headers *header,
    + const unsigned long end)
    +{
    + struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;
    +
    + return pch_pic_acpi_init(htvec_priv->htvec_domain, pchpic_entry);
    +}
    +
    +static int __init
    +pch_msi_parse_madt(union acpi_subtable_headers *header,
    + const unsigned long end)
    +{
    + struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;
    +
    + return pch_msi_acpi_init(htvec_priv->htvec_domain, pchmsi_entry);
    +}
    +
    +static int __init acpi_cascade_irqdomain_init(void)
    +{
    + acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC,
    + pch_pic_parse_madt, 0);
    + acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC,
    + pch_msi_parse_madt, 0);
    + return 0;
    +}
    +
    +int __init htvec_acpi_init(struct irq_domain *parent,
    + struct acpi_madt_ht_pic *acpi_htvec)
    +{
    + int i, ret;
    + int num_parents, parent_irq[8];
    + struct fwnode_handle *domain_handle;
    +
    + if (!acpi_htvec)
    + return -EINVAL;
    +
    + num_parents = HTVEC_MAX_PARENT_IRQ;
    +
    + domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_htvec);
    + if (!domain_handle) {
    + pr_err("Unable to allocate domain handle\n");
    + return -ENOMEM;
    + }
    +
    + /* Interrupt may come from any of the 8 interrupt lines */
    + for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++)
    + parent_irq[i] = irq_create_mapping(parent, acpi_htvec->cascade[i]);
    +
    + ret = htvec_init(acpi_htvec->address, acpi_htvec->size,
    + num_parents, parent_irq, domain_handle);
    +
    + if (!ret)
    + acpi_cascade_irqdomain_init();
    + else
    + irq_domain_free_fwnode(domain_handle);
    +
    + return ret;
    +}
    +
    +#endif
    --
    1.8.3.1
    \
     
     \ /
      Last update: 2022-07-15 09:07    [W:4.237 / U:0.092 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site