^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Freescale SCFG MSI(-X) support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2016 Freescale Semiconductor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Minghuan Lian <Minghuan.Lian@nxp.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/msi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/irqchip/chained_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/irqdomain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/of_pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/dma-iommu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define MSI_IRQS_PER_MSIR 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define MSI_MSIR_OFFSET 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define MSI_LS1043V1_1_IRQS_PER_MSIR 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define MSI_LS1043V1_1_MSIR_OFFSET 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct ls_scfg_msi_cfg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u32 ibs_shift; /* Shift of interrupt bit select */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u32 msir_irqs; /* The irq number per MSIR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u32 msir_base; /* The base address of MSIR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct ls_scfg_msir {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct ls_scfg_msi *msi_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) unsigned int gic_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) unsigned int bit_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) unsigned int bit_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned int srs; /* Shared interrupt register select */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct ls_scfg_msi {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct irq_domain *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct irq_domain *msi_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) phys_addr_t msiir_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct ls_scfg_msi_cfg *cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u32 msir_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct ls_scfg_msir *msir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u32 irqs_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned long *used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static struct irq_chip ls_scfg_msi_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) .name = "MSI",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .irq_mask = pci_msi_mask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .irq_unmask = pci_msi_unmask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static struct msi_domain_info ls_scfg_msi_domain_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .flags = (MSI_FLAG_USE_DEF_DOM_OPS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) MSI_FLAG_USE_DEF_CHIP_OPS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) MSI_FLAG_PCI_MSIX),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) .chip = &ls_scfg_msi_irq_chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static int msi_affinity_flag = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static int __init early_parse_ls_scfg_msi(char *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (p && strncmp(p, "no-affinity", 11) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) msi_affinity_flag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) msi_affinity_flag = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) early_param("lsmsi", early_parse_ls_scfg_msi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) msg->address_hi = upper_32_bits(msi_data->msiir_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) msg->address_lo = lower_32_bits(msi_data->msiir_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) msg->data = data->hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (msi_affinity_flag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) const struct cpumask *mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) mask = irq_data_get_effective_affinity_mask(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) msg->data |= cpumask_first(mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) const struct cpumask *mask, bool force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(irq_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) u32 cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (!msi_affinity_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) cpu = cpumask_any_and(mask, cpu_online_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) cpu = cpumask_first(mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (cpu >= msi_data->msir_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (msi_data->msir[cpu].gic_irq <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) pr_warn("cannot bind the irq to cpu%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) irq_data_update_effective_affinity(irq_data, cpumask_of(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return IRQ_SET_MASK_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static struct irq_chip ls_scfg_msi_parent_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .name = "SCFG",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .irq_compose_msi_msg = ls_scfg_msi_compose_msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .irq_set_affinity = ls_scfg_msi_set_affinity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned int virq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) unsigned int nr_irqs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) void *args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) msi_alloc_info_t *info = args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct ls_scfg_msi *msi_data = domain->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int pos, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) WARN_ON(nr_irqs != 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) spin_lock(&msi_data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) pos = find_first_zero_bit(msi_data->used, msi_data->irqs_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (pos < msi_data->irqs_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) __set_bit(pos, msi_data->used);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) err = -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) spin_unlock(&msi_data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) err = iommu_dma_prepare_msi(info->desc, msi_data->msiir_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) irq_domain_set_info(domain, virq, pos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) &ls_scfg_msi_parent_chip, msi_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) handle_simple_irq, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) unsigned int virq, unsigned int nr_irqs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct irq_data *d = irq_domain_get_irq_data(domain, virq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) int pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) pos = d->hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (pos < 0 || pos >= msi_data->irqs_num) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) pr_err("failed to teardown msi. Invalid hwirq %d\n", pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) spin_lock(&msi_data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) __clear_bit(pos, msi_data->used);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) spin_unlock(&msi_data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static const struct irq_domain_ops ls_scfg_msi_domain_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .alloc = ls_scfg_msi_domain_irq_alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .free = ls_scfg_msi_domain_irq_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) struct ls_scfg_msi *msi_data = msir->msi_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) int pos, size, virq, hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) chained_irq_enter(irq_desc_get_chip(desc), desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) val = ioread32be(msir->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) pos = msir->bit_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) size = msir->bit_end + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) for_each_set_bit_from(pos, &val, size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) msir->srs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) virq = irq_find_mapping(msi_data->parent, hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (virq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) generic_handle_irq(virq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) chained_irq_exit(irq_desc_get_chip(desc), desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* Initialize MSI domain parent */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) msi_data->parent = irq_domain_add_linear(NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) msi_data->irqs_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) &ls_scfg_msi_domain_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) msi_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (!msi_data->parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) dev_err(&msi_data->pdev->dev, "failed to create IRQ domain\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) msi_data->msi_domain = pci_msi_create_irq_domain(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) of_node_to_fwnode(msi_data->pdev->dev.of_node),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) &ls_scfg_msi_domain_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) msi_data->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (!msi_data->msi_domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) dev_err(&msi_data->pdev->dev, "failed to create MSI domain\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) irq_domain_remove(msi_data->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct ls_scfg_msir *msir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) int virq, i, hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) virq = platform_get_irq(msi_data->pdev, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (virq <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) msir = &msi_data->msir[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) msir->index = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) msir->msi_data = msi_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) msir->gic_irq = virq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) msir->reg = msi_data->regs + msi_data->cfg->msir_base + 4 * index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (msi_data->cfg->msir_irqs == MSI_LS1043V1_1_IRQS_PER_MSIR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) msir->bit_start = 32 - ((msir->index + 1) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) MSI_LS1043V1_1_IRQS_PER_MSIR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) msir->bit_end = msir->bit_start +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) MSI_LS1043V1_1_IRQS_PER_MSIR - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) msir->bit_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) msir->bit_end = msi_data->cfg->msir_irqs - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) irq_set_chained_handler_and_data(msir->gic_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) ls_scfg_msi_irq_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) msir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (msi_affinity_flag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /* Associate MSIR interrupt to the cpu */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) irq_set_affinity(msir->gic_irq, get_cpu_mask(index));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) msir->srs = 0; /* This value is determined by the CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) msir->srs = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /* Release the hwirqs corresponding to this MSIR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (!msi_affinity_flag || msir->index == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) hwirq = i << msi_data->cfg->ibs_shift | msir->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) bitmap_clear(msi_data->used, hwirq, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct ls_scfg_msi *msi_data = msir->msi_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) int i, hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (msir->gic_irq > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) hwirq = i << msi_data->cfg->ibs_shift | msir->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) bitmap_set(msi_data->used, hwirq, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static struct ls_scfg_msi_cfg ls1021_msi_cfg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) .ibs_shift = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) .msir_irqs = MSI_IRQS_PER_MSIR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .msir_base = MSI_MSIR_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static struct ls_scfg_msi_cfg ls1046_msi_cfg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .ibs_shift = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) .msir_irqs = MSI_IRQS_PER_MSIR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .msir_base = MSI_MSIR_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static struct ls_scfg_msi_cfg ls1043_v1_1_msi_cfg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .ibs_shift = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .msir_irqs = MSI_LS1043V1_1_IRQS_PER_MSIR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .msir_base = MSI_LS1043V1_1_MSIR_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) static const struct of_device_id ls_scfg_msi_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* The following two misspelled compatibles are obsolete */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) { .compatible = "fsl,1s1021a-msi", .data = &ls1021_msi_cfg},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) { .compatible = "fsl,1s1043a-msi", .data = &ls1021_msi_cfg},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) { .compatible = "fsl,ls1012a-msi", .data = &ls1021_msi_cfg },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) { .compatible = "fsl,ls1043a-v1.1-msi", .data = &ls1043_v1_1_msi_cfg },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) MODULE_DEVICE_TABLE(of, ls_scfg_msi_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static int ls_scfg_msi_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) const struct of_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) struct ls_scfg_msi *msi_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) match = of_match_device(ls_scfg_msi_id, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (!match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (!msi_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) msi_data->regs = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (IS_ERR(msi_data->regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) dev_err(&pdev->dev, "failed to initialize 'regs'\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return PTR_ERR(msi_data->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) msi_data->msiir_addr = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) msi_data->pdev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) spin_lock_init(&msi_data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) msi_data->irqs_num = MSI_IRQS_PER_MSIR *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) (1 << msi_data->cfg->ibs_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) msi_data->used = devm_kcalloc(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) BITS_TO_LONGS(msi_data->irqs_num),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) sizeof(*msi_data->used),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (!msi_data->used)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * Reserve all the hwirqs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) * The available hwirqs will be released in ls1_msi_setup_hwirq()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) bitmap_set(msi_data->used, 0, msi_data->irqs_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) msi_data->msir_num = of_irq_count(pdev->dev.of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (msi_affinity_flag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) u32 cpu_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) cpu_num = num_possible_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (msi_data->msir_num >= cpu_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) msi_data->msir_num = cpu_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) msi_affinity_flag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) sizeof(*msi_data->msir),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (!msi_data->msir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) for (i = 0; i < msi_data->msir_num; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) ls_scfg_msi_setup_hwirq(msi_data, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ret = ls_scfg_msi_domains_init(msi_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) platform_set_drvdata(pdev, msi_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) static int ls_scfg_msi_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) for (i = 0; i < msi_data->msir_num; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) ls_scfg_msi_teardown_hwirq(&msi_data->msir[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) irq_domain_remove(msi_data->msi_domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) irq_domain_remove(msi_data->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) platform_set_drvdata(pdev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static struct platform_driver ls_scfg_msi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) .name = "ls-scfg-msi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .of_match_table = ls_scfg_msi_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) .probe = ls_scfg_msi_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) .remove = ls_scfg_msi_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) module_platform_driver(ls_scfg_msi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@nxp.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) MODULE_DESCRIPTION("Freescale Layerscape SCFG MSI controller driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) MODULE_LICENSE("GPL v2");