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