irqchip/ls-scfg-msi: Add LS1046a MSI support

LS1046a includes 4 MSIRs, each MSIR is assigned a dedicate GIC
SPI interrupt and provides 32 MSI interrupts. Compared to previous
MSI, LS1046a's IBS(interrupt bit select) shift is changed to 2 and
total MSI interrupt number is changed to 128.

The patch adds structure 'ls_scfg_msir' to describe MSIR setting and
'ibs_shift' to store the different value between the SoCs.

Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

authored by

Minghuan Lian and committed by
Marc Zyngier
4dd5da65 cb342168

+130 -35
+130 -35
drivers/irqchip/irq-ls-scfg-msi.c
··· 17 #include <linux/irq.h> 18 #include <linux/irqchip/chained_irq.h> 19 #include <linux/irqdomain.h> 20 #include <linux/of_pci.h> 21 #include <linux/of_platform.h> 22 #include <linux/spinlock.h> 23 24 - #define MSI_MAX_IRQS 32 25 - #define MSI_IBS_SHIFT 3 26 - #define MSIR 4 27 28 struct ls_scfg_msi { 29 spinlock_t lock; ··· 43 struct irq_domain *msi_domain; 44 void __iomem *regs; 45 phys_addr_t msiir_addr; 46 - int irq; 47 - DECLARE_BITMAP(used, MSI_MAX_IRQS); 48 }; 49 50 static struct irq_chip ls_scfg_msi_irq_chip = { ··· 69 70 msg->address_hi = upper_32_bits(msi_data->msiir_addr); 71 msg->address_lo = lower_32_bits(msi_data->msiir_addr); 72 - msg->data = data->hwirq << MSI_IBS_SHIFT; 73 } 74 75 static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, ··· 95 WARN_ON(nr_irqs != 1); 96 97 spin_lock(&msi_data->lock); 98 - pos = find_first_zero_bit(msi_data->used, MSI_MAX_IRQS); 99 - if (pos < MSI_MAX_IRQS) 100 __set_bit(pos, msi_data->used); 101 else 102 err = -ENOSPC; ··· 120 int pos; 121 122 pos = d->hwirq; 123 - if (pos < 0 || pos >= MSI_MAX_IRQS) { 124 pr_err("failed to teardown msi. Invalid hwirq %d\n", pos); 125 return; 126 } ··· 137 138 static void ls_scfg_msi_irq_handler(struct irq_desc *desc) 139 { 140 - struct ls_scfg_msi *msi_data = irq_desc_get_handler_data(desc); 141 unsigned long val; 142 - int pos, virq; 143 144 chained_irq_enter(irq_desc_get_chip(desc), desc); 145 146 - val = ioread32be(msi_data->regs + MSIR); 147 - for_each_set_bit(pos, &val, MSI_MAX_IRQS) { 148 - virq = irq_find_mapping(msi_data->parent, (31 - pos)); 149 if (virq) 150 generic_handle_irq(virq); 151 } ··· 159 { 160 /* Initialize MSI domain parent */ 161 msi_data->parent = irq_domain_add_linear(NULL, 162 - MSI_MAX_IRQS, 163 &ls_scfg_msi_domain_ops, 164 msi_data); 165 if (!msi_data->parent) { ··· 180 return 0; 181 } 182 183 static int ls_scfg_msi_probe(struct platform_device *pdev) 184 { 185 struct ls_scfg_msi *msi_data; 186 struct resource *res; 187 - int ret; 188 189 msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL); 190 if (!msi_data) 191 return -ENOMEM; 192 193 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 194 msi_data->regs = devm_ioremap_resource(&pdev->dev, res); ··· 269 } 270 msi_data->msiir_addr = res->start; 271 272 - msi_data->irq = platform_get_irq(pdev, 0); 273 - if (msi_data->irq <= 0) { 274 - dev_err(&pdev->dev, "failed to get MSI irq\n"); 275 - return -ENODEV; 276 - } 277 - 278 msi_data->pdev = pdev; 279 spin_lock_init(&msi_data->lock); 280 281 ret = ls_scfg_msi_domains_init(msi_data); 282 if (ret) 283 return ret; 284 - 285 - irq_set_chained_handler_and_data(msi_data->irq, 286 - ls_scfg_msi_irq_handler, 287 - msi_data); 288 289 platform_set_drvdata(pdev, msi_data); 290 ··· 308 static int ls_scfg_msi_remove(struct platform_device *pdev) 309 { 310 struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev); 311 312 - irq_set_chained_handler_and_data(msi_data->irq, NULL, NULL); 313 314 irq_domain_remove(msi_data->msi_domain); 315 irq_domain_remove(msi_data->parent); ··· 320 321 return 0; 322 } 323 - 324 - static const struct of_device_id ls_scfg_msi_id[] = { 325 - { .compatible = "fsl,1s1021a-msi", }, /* a typo */ 326 - { .compatible = "fsl,1s1043a-msi", }, /* a typo */ 327 - { .compatible = "fsl,ls1021a-msi", }, 328 - { .compatible = "fsl,ls1043a-msi", }, 329 - {}, 330 - }; 331 332 static struct platform_driver ls_scfg_msi_driver = { 333 .driver = {
··· 17 #include <linux/irq.h> 18 #include <linux/irqchip/chained_irq.h> 19 #include <linux/irqdomain.h> 20 + #include <linux/of_irq.h> 21 #include <linux/of_pci.h> 22 #include <linux/of_platform.h> 23 #include <linux/spinlock.h> 24 25 + #define MSI_IRQS_PER_MSIR 32 26 + #define MSI_MSIR_OFFSET 4 27 + 28 + struct ls_scfg_msi_cfg { 29 + u32 ibs_shift; /* Shift of interrupt bit select */ 30 + }; 31 + 32 + struct ls_scfg_msir { 33 + struct ls_scfg_msi *msi_data; 34 + unsigned int index; 35 + unsigned int gic_irq; 36 + void __iomem *reg; 37 + }; 38 39 struct ls_scfg_msi { 40 spinlock_t lock; ··· 32 struct irq_domain *msi_domain; 33 void __iomem *regs; 34 phys_addr_t msiir_addr; 35 + struct ls_scfg_msi_cfg *cfg; 36 + u32 msir_num; 37 + struct ls_scfg_msir *msir; 38 + u32 irqs_num; 39 + unsigned long *used; 40 }; 41 42 static struct irq_chip ls_scfg_msi_irq_chip = { ··· 55 56 msg->address_hi = upper_32_bits(msi_data->msiir_addr); 57 msg->address_lo = lower_32_bits(msi_data->msiir_addr); 58 + msg->data = data->hwirq; 59 } 60 61 static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, ··· 81 WARN_ON(nr_irqs != 1); 82 83 spin_lock(&msi_data->lock); 84 + pos = find_first_zero_bit(msi_data->used, msi_data->irqs_num); 85 + if (pos < msi_data->irqs_num) 86 __set_bit(pos, msi_data->used); 87 else 88 err = -ENOSPC; ··· 106 int pos; 107 108 pos = d->hwirq; 109 + if (pos < 0 || pos >= msi_data->irqs_num) { 110 pr_err("failed to teardown msi. Invalid hwirq %d\n", pos); 111 return; 112 } ··· 123 124 static void ls_scfg_msi_irq_handler(struct irq_desc *desc) 125 { 126 + struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc); 127 + struct ls_scfg_msi *msi_data = msir->msi_data; 128 unsigned long val; 129 + int pos, virq, hwirq; 130 131 chained_irq_enter(irq_desc_get_chip(desc), desc); 132 133 + val = ioread32be(msir->reg); 134 + for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) { 135 + hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index; 136 + virq = irq_find_mapping(msi_data->parent, hwirq); 137 if (virq) 138 generic_handle_irq(virq); 139 } ··· 143 { 144 /* Initialize MSI domain parent */ 145 msi_data->parent = irq_domain_add_linear(NULL, 146 + msi_data->irqs_num, 147 &ls_scfg_msi_domain_ops, 148 msi_data); 149 if (!msi_data->parent) { ··· 164 return 0; 165 } 166 167 + static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index) 168 + { 169 + struct ls_scfg_msir *msir; 170 + int virq, i, hwirq; 171 + 172 + virq = platform_get_irq(msi_data->pdev, index); 173 + if (virq <= 0) 174 + return -ENODEV; 175 + 176 + msir = &msi_data->msir[index]; 177 + msir->index = index; 178 + msir->msi_data = msi_data; 179 + msir->gic_irq = virq; 180 + msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index; 181 + 182 + irq_set_chained_handler_and_data(msir->gic_irq, 183 + ls_scfg_msi_irq_handler, 184 + msir); 185 + 186 + /* Release the hwirqs corresponding to this MSIR */ 187 + for (i = 0; i < MSI_IRQS_PER_MSIR; i++) { 188 + hwirq = i << msi_data->cfg->ibs_shift | msir->index; 189 + bitmap_clear(msi_data->used, hwirq, 1); 190 + } 191 + 192 + return 0; 193 + } 194 + 195 + static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir) 196 + { 197 + struct ls_scfg_msi *msi_data = msir->msi_data; 198 + int i, hwirq; 199 + 200 + if (msir->gic_irq > 0) 201 + irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL); 202 + 203 + for (i = 0; i < MSI_IRQS_PER_MSIR; i++) { 204 + hwirq = i << msi_data->cfg->ibs_shift | msir->index; 205 + bitmap_set(msi_data->used, hwirq, 1); 206 + } 207 + 208 + return 0; 209 + } 210 + 211 + static struct ls_scfg_msi_cfg ls1021_msi_cfg = { 212 + .ibs_shift = 3, 213 + }; 214 + 215 + static struct ls_scfg_msi_cfg ls1046_msi_cfg = { 216 + .ibs_shift = 2, 217 + }; 218 + 219 + static const struct of_device_id ls_scfg_msi_id[] = { 220 + /* The following two misspelled compatibles are obsolete */ 221 + { .compatible = "fsl,1s1021a-msi", .data = &ls1021_msi_cfg}, 222 + { .compatible = "fsl,1s1043a-msi", .data = &ls1021_msi_cfg}, 223 + 224 + { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg }, 225 + { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg }, 226 + { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg }, 227 + {}, 228 + }; 229 + MODULE_DEVICE_TABLE(of, ls_scfg_msi_id); 230 + 231 static int ls_scfg_msi_probe(struct platform_device *pdev) 232 { 233 + const struct of_device_id *match; 234 struct ls_scfg_msi *msi_data; 235 struct resource *res; 236 + int i, ret; 237 + 238 + match = of_match_device(ls_scfg_msi_id, &pdev->dev); 239 + if (!match) 240 + return -ENODEV; 241 242 msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL); 243 if (!msi_data) 244 return -ENOMEM; 245 + 246 + msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data; 247 248 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 249 msi_data->regs = devm_ioremap_resource(&pdev->dev, res); ··· 182 } 183 msi_data->msiir_addr = res->start; 184 185 msi_data->pdev = pdev; 186 spin_lock_init(&msi_data->lock); 187 + 188 + msi_data->irqs_num = MSI_IRQS_PER_MSIR * 189 + (1 << msi_data->cfg->ibs_shift); 190 + msi_data->used = devm_kcalloc(&pdev->dev, 191 + BITS_TO_LONGS(msi_data->irqs_num), 192 + sizeof(*msi_data->used), 193 + GFP_KERNEL); 194 + if (!msi_data->used) 195 + return -ENOMEM; 196 + /* 197 + * Reserve all the hwirqs 198 + * The available hwirqs will be released in ls1_msi_setup_hwirq() 199 + */ 200 + bitmap_set(msi_data->used, 0, msi_data->irqs_num); 201 + 202 + msi_data->msir_num = of_irq_count(pdev->dev.of_node); 203 + msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num, 204 + sizeof(*msi_data->msir), 205 + GFP_KERNEL); 206 + if (!msi_data->msir) 207 + return -ENOMEM; 208 + 209 + for (i = 0; i < msi_data->msir_num; i++) 210 + ls_scfg_msi_setup_hwirq(msi_data, i); 211 212 ret = ls_scfg_msi_domains_init(msi_data); 213 if (ret) 214 return ret; 215 216 platform_set_drvdata(pdev, msi_data); 217 ··· 207 static int ls_scfg_msi_remove(struct platform_device *pdev) 208 { 209 struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev); 210 + int i; 211 212 + for (i = 0; i < msi_data->msir_num; i++) 213 + ls_scfg_msi_teardown_hwirq(&msi_data->msir[i]); 214 215 irq_domain_remove(msi_data->msi_domain); 216 irq_domain_remove(msi_data->parent); ··· 217 218 return 0; 219 } 220 221 static struct platform_driver ls_scfg_msi_driver = { 222 .driver = {