1 /* 2 * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. All rights reserved. 3 * 4 * Author: Tony Li <tony.li@freescale.com> 5 * Jason Jin <Jason.jin@freescale.com> 6 * 7 * The hwirq alloc and free code reuse from sysdev/mpic_msi.c 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; version 2 of the 12 * License. 13 * 14 */ 15 #include <linux/irq.h> 16 #include <linux/bootmem.h> 17 #include <linux/msi.h> 18 #include <linux/pci.h> 19 #include <linux/of_platform.h> 20 #include <sysdev/fsl_soc.h> 21 #include <asm/prom.h> 22 #include <asm/hw_irq.h> 23 #include <asm/ppc-pci.h> 24 #include "fsl_msi.h" 25 26 struct fsl_msi_feature { 27 u32 fsl_pic_ip; 28 u32 msiir_offset; 29 }; 30 31 static struct fsl_msi *fsl_msi; 32 33 static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) 34 { 35 return in_be32(base + (reg >> 2)); 36 } 37 38 /* 39 * We do not need this actually. The MSIR register has been read once 40 * in the cascade interrupt. So, this MSI interrupt has been acked 41 */ 42 static void fsl_msi_end_irq(unsigned int virq) 43 { 44 } 45 46 static struct irq_chip fsl_msi_chip = { 47 .mask = mask_msi_irq, 48 .unmask = unmask_msi_irq, 49 .ack = fsl_msi_end_irq, 50 .typename = " FSL-MSI ", 51 }; 52 53 static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, 54 irq_hw_number_t hw) 55 { 56 struct irq_chip *chip = &fsl_msi_chip; 57 58 get_irq_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING; 59 60 set_irq_chip_and_handler(virq, chip, handle_edge_irq); 61 62 return 0; 63 } 64 65 static struct irq_host_ops fsl_msi_host_ops = { 66 .map = fsl_msi_host_map, 67 }; 68 69 static int fsl_msi_init_allocator(struct fsl_msi *msi_data) 70 { 71 int rc; 72 73 rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS, 74 msi_data->irqhost->of_node); 75 if (rc) 76 return rc; 77 78 rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap); 79 if (rc < 0) { 80 msi_bitmap_free(&msi_data->bitmap); 81 return rc; 82 } 83 84 return 0; 85 } 86 87 static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type) 88 { 89 if (type == PCI_CAP_ID_MSIX) 90 pr_debug("fslmsi: MSI-X untested, trying anyway.\n"); 91 92 return 0; 93 } 94 95 static void fsl_teardown_msi_irqs(struct pci_dev *pdev) 96 { 97 struct msi_desc *entry; 98 struct fsl_msi *msi_data = fsl_msi; 99 100 list_for_each_entry(entry, &pdev->msi_list, list) { 101 if (entry->irq == NO_IRQ) 102 continue; 103 set_irq_msi(entry->irq, NULL); 104 msi_bitmap_free_hwirqs(&msi_data->bitmap, 105 virq_to_hw(entry->irq), 1); 106 irq_dispose_mapping(entry->irq); 107 } 108 109 return; 110 } 111 112 static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, 113 struct msi_msg *msg) 114 { 115 struct fsl_msi *msi_data = fsl_msi; 116 117 msg->address_lo = msi_data->msi_addr_lo; 118 msg->address_hi = msi_data->msi_addr_hi; 119 msg->data = hwirq; 120 121 pr_debug("%s: allocated srs: %d, ibs: %d\n", 122 __func__, hwirq / IRQS_PER_MSI_REG, hwirq % IRQS_PER_MSI_REG); 123 } 124 125 static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) 126 { 127 int rc, hwirq; 128 unsigned int virq; 129 struct msi_desc *entry; 130 struct msi_msg msg; 131 struct fsl_msi *msi_data = fsl_msi; 132 133 list_for_each_entry(entry, &pdev->msi_list, list) { 134 hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); 135 if (hwirq < 0) { 136 rc = hwirq; 137 pr_debug("%s: fail allocating msi interrupt\n", 138 __func__); 139 goto out_free; 140 } 141 142 virq = irq_create_mapping(msi_data->irqhost, hwirq); 143 144 if (virq == NO_IRQ) { 145 pr_debug("%s: fail mapping hwirq 0x%x\n", 146 __func__, hwirq); 147 msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); 148 rc = -ENOSPC; 149 goto out_free; 150 } 151 set_irq_msi(virq, entry); 152 153 fsl_compose_msi_msg(pdev, hwirq, &msg); 154 write_msi_msg(virq, &msg); 155 } 156 return 0; 157 158 out_free: 159 return rc; 160 } 161 162 static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) 163 { 164 unsigned int cascade_irq; 165 struct fsl_msi *msi_data = fsl_msi; 166 int msir_index = -1; 167 u32 msir_value = 0; 168 u32 intr_index; 169 u32 have_shift = 0; 170 171 spin_lock(&desc->lock); 172 if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) { 173 if (desc->chip->mask_ack) 174 desc->chip->mask_ack(irq); 175 else { 176 desc->chip->mask(irq); 177 desc->chip->ack(irq); 178 } 179 } 180 181 if (unlikely(desc->status & IRQ_INPROGRESS)) 182 goto unlock; 183 184 msir_index = (int)desc->handler_data; 185 186 if (msir_index >= NR_MSI_REG) 187 cascade_irq = NO_IRQ; 188 189 desc->status |= IRQ_INPROGRESS; 190 switch (fsl_msi->feature & FSL_PIC_IP_MASK) { 191 case FSL_PIC_IP_MPIC: 192 msir_value = fsl_msi_read(msi_data->msi_regs, 193 msir_index * 0x10); 194 break; 195 case FSL_PIC_IP_IPIC: 196 msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4); 197 break; 198 } 199 200 while (msir_value) { 201 intr_index = ffs(msir_value) - 1; 202 203 cascade_irq = irq_linear_revmap(msi_data->irqhost, 204 msir_index * IRQS_PER_MSI_REG + 205 intr_index + have_shift); 206 if (cascade_irq != NO_IRQ) 207 generic_handle_irq(cascade_irq); 208 have_shift += intr_index + 1; 209 msir_value = msir_value >> (intr_index + 1); 210 } 211 desc->status &= ~IRQ_INPROGRESS; 212 213 switch (msi_data->feature & FSL_PIC_IP_MASK) { 214 case FSL_PIC_IP_MPIC: 215 desc->chip->eoi(irq); 216 break; 217 case FSL_PIC_IP_IPIC: 218 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) 219 desc->chip->unmask(irq); 220 break; 221 } 222 unlock: 223 spin_unlock(&desc->lock); 224 } 225 226 static int __devinit fsl_of_msi_probe(struct of_device *dev, 227 const struct of_device_id *match) 228 { 229 struct fsl_msi *msi; 230 struct resource res; 231 int err, i, count; 232 int rc; 233 int virt_msir; 234 const u32 *p; 235 struct fsl_msi_feature *features = match->data; 236 237 printk(KERN_DEBUG "Setting up Freescale MSI support\n"); 238 239 msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL); 240 if (!msi) { 241 dev_err(&dev->dev, "No memory for MSI structure\n"); 242 err = -ENOMEM; 243 goto error_out; 244 } 245 246 msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR, 247 NR_MSI_IRQS, &fsl_msi_host_ops, 0); 248 249 if (msi->irqhost == NULL) { 250 dev_err(&dev->dev, "No memory for MSI irqhost\n"); 251 err = -ENOMEM; 252 goto error_out; 253 } 254 255 /* Get the MSI reg base */ 256 err = of_address_to_resource(dev->node, 0, &res); 257 if (err) { 258 dev_err(&dev->dev, "%s resource error!\n", 259 dev->node->full_name); 260 goto error_out; 261 } 262 263 msi->msi_regs = ioremap(res.start, res.end - res.start + 1); 264 if (!msi->msi_regs) { 265 dev_err(&dev->dev, "ioremap problem failed\n"); 266 goto error_out; 267 } 268 269 msi->feature = features->fsl_pic_ip; 270 271 msi->irqhost->host_data = msi; 272 273 msi->msi_addr_hi = 0x0; 274 msi->msi_addr_lo = res.start + features->msiir_offset; 275 276 rc = fsl_msi_init_allocator(msi); 277 if (rc) { 278 dev_err(&dev->dev, "Error allocating MSI bitmap\n"); 279 goto error_out; 280 } 281 282 p = of_get_property(dev->node, "interrupts", &count); 283 if (!p) { 284 dev_err(&dev->dev, "no interrupts property found on %s\n", 285 dev->node->full_name); 286 err = -ENODEV; 287 goto error_out; 288 } 289 if (count % 8 != 0) { 290 dev_err(&dev->dev, "Malformed interrupts property on %s\n", 291 dev->node->full_name); 292 err = -EINVAL; 293 goto error_out; 294 } 295 296 count /= sizeof(u32); 297 for (i = 0; i < count / 2; i++) { 298 if (i > NR_MSI_REG) 299 break; 300 virt_msir = irq_of_parse_and_map(dev->node, i); 301 if (virt_msir != NO_IRQ) { 302 set_irq_data(virt_msir, (void *)i); 303 set_irq_chained_handler(virt_msir, fsl_msi_cascade); 304 } 305 } 306 307 fsl_msi = msi; 308 309 WARN_ON(ppc_md.setup_msi_irqs); 310 ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; 311 ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs; 312 ppc_md.msi_check_device = fsl_msi_check_device; 313 return 0; 314 error_out: 315 kfree(msi); 316 return err; 317 } 318 319 static const struct fsl_msi_feature mpic_msi_feature = { 320 .fsl_pic_ip = FSL_PIC_IP_MPIC, 321 .msiir_offset = 0x140, 322 }; 323 324 static const struct fsl_msi_feature ipic_msi_feature = { 325 .fsl_pic_ip = FSL_PIC_IP_IPIC, 326 .msiir_offset = 0x38, 327 }; 328 329 static const struct of_device_id fsl_of_msi_ids[] = { 330 { 331 .compatible = "fsl,mpic-msi", 332 .data = (void *)&mpic_msi_feature, 333 }, 334 { 335 .compatible = "fsl,ipic-msi", 336 .data = (void *)&ipic_msi_feature, 337 }, 338 {} 339 }; 340 341 static struct of_platform_driver fsl_of_msi_driver = { 342 .name = "fsl-msi", 343 .match_table = fsl_of_msi_ids, 344 .probe = fsl_of_msi_probe, 345 }; 346 347 static __init int fsl_of_msi_init(void) 348 { 349 return of_register_platform_driver(&fsl_of_msi_driver); 350 } 351 352 subsys_initcall(fsl_of_msi_init); 353