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 struct pci_controller *hose = pci_bus_to_host(pdev->bus); 117 u32 base = 0; 118 119 pci_bus_read_config_dword(hose->bus, 120 PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base); 121 122 msg->address_lo = msi_data->msi_addr_lo + base; 123 msg->address_hi = msi_data->msi_addr_hi; 124 msg->data = hwirq; 125 126 pr_debug("%s: allocated srs: %d, ibs: %d\n", 127 __func__, hwirq / IRQS_PER_MSI_REG, hwirq % IRQS_PER_MSI_REG); 128 } 129 130 static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) 131 { 132 int rc, hwirq; 133 unsigned int virq; 134 struct msi_desc *entry; 135 struct msi_msg msg; 136 struct fsl_msi *msi_data = fsl_msi; 137 138 list_for_each_entry(entry, &pdev->msi_list, list) { 139 hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); 140 if (hwirq < 0) { 141 rc = hwirq; 142 pr_debug("%s: fail allocating msi interrupt\n", 143 __func__); 144 goto out_free; 145 } 146 147 virq = irq_create_mapping(msi_data->irqhost, hwirq); 148 149 if (virq == NO_IRQ) { 150 pr_debug("%s: fail mapping hwirq 0x%x\n", 151 __func__, hwirq); 152 msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); 153 rc = -ENOSPC; 154 goto out_free; 155 } 156 set_irq_msi(virq, entry); 157 158 fsl_compose_msi_msg(pdev, hwirq, &msg); 159 write_msi_msg(virq, &msg); 160 } 161 return 0; 162 163 out_free: 164 return rc; 165 } 166 167 static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) 168 { 169 unsigned int cascade_irq; 170 struct fsl_msi *msi_data = fsl_msi; 171 int msir_index = -1; 172 u32 msir_value = 0; 173 u32 intr_index; 174 u32 have_shift = 0; 175 176 spin_lock(&desc->lock); 177 if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) { 178 if (desc->chip->mask_ack) 179 desc->chip->mask_ack(irq); 180 else { 181 desc->chip->mask(irq); 182 desc->chip->ack(irq); 183 } 184 } 185 186 if (unlikely(desc->status & IRQ_INPROGRESS)) 187 goto unlock; 188 189 msir_index = (int)desc->handler_data; 190 191 if (msir_index >= NR_MSI_REG) 192 cascade_irq = NO_IRQ; 193 194 desc->status |= IRQ_INPROGRESS; 195 switch (fsl_msi->feature & FSL_PIC_IP_MASK) { 196 case FSL_PIC_IP_MPIC: 197 msir_value = fsl_msi_read(msi_data->msi_regs, 198 msir_index * 0x10); 199 break; 200 case FSL_PIC_IP_IPIC: 201 msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4); 202 break; 203 } 204 205 while (msir_value) { 206 intr_index = ffs(msir_value) - 1; 207 208 cascade_irq = irq_linear_revmap(msi_data->irqhost, 209 msir_index * IRQS_PER_MSI_REG + 210 intr_index + have_shift); 211 if (cascade_irq != NO_IRQ) 212 generic_handle_irq(cascade_irq); 213 have_shift += intr_index + 1; 214 msir_value = msir_value >> (intr_index + 1); 215 } 216 desc->status &= ~IRQ_INPROGRESS; 217 218 switch (msi_data->feature & FSL_PIC_IP_MASK) { 219 case FSL_PIC_IP_MPIC: 220 desc->chip->eoi(irq); 221 break; 222 case FSL_PIC_IP_IPIC: 223 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) 224 desc->chip->unmask(irq); 225 break; 226 } 227 unlock: 228 spin_unlock(&desc->lock); 229 } 230 231 static int __devinit fsl_of_msi_probe(struct of_device *dev, 232 const struct of_device_id *match) 233 { 234 struct fsl_msi *msi; 235 struct resource res; 236 int err, i, count; 237 int rc; 238 int virt_msir; 239 const u32 *p; 240 struct fsl_msi_feature *features = match->data; 241 242 printk(KERN_DEBUG "Setting up Freescale MSI support\n"); 243 244 msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL); 245 if (!msi) { 246 dev_err(&dev->dev, "No memory for MSI structure\n"); 247 err = -ENOMEM; 248 goto error_out; 249 } 250 251 msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR, 252 NR_MSI_IRQS, &fsl_msi_host_ops, 0); 253 254 if (msi->irqhost == NULL) { 255 dev_err(&dev->dev, "No memory for MSI irqhost\n"); 256 err = -ENOMEM; 257 goto error_out; 258 } 259 260 /* Get the MSI reg base */ 261 err = of_address_to_resource(dev->node, 0, &res); 262 if (err) { 263 dev_err(&dev->dev, "%s resource error!\n", 264 dev->node->full_name); 265 goto error_out; 266 } 267 268 msi->msi_regs = ioremap(res.start, res.end - res.start + 1); 269 if (!msi->msi_regs) { 270 dev_err(&dev->dev, "ioremap problem failed\n"); 271 goto error_out; 272 } 273 274 msi->feature = features->fsl_pic_ip; 275 276 msi->irqhost->host_data = msi; 277 278 msi->msi_addr_hi = 0x0; 279 msi->msi_addr_lo = features->msiir_offset + (res.start & 0xfffff); 280 281 rc = fsl_msi_init_allocator(msi); 282 if (rc) { 283 dev_err(&dev->dev, "Error allocating MSI bitmap\n"); 284 goto error_out; 285 } 286 287 p = of_get_property(dev->node, "interrupts", &count); 288 if (!p) { 289 dev_err(&dev->dev, "no interrupts property found on %s\n", 290 dev->node->full_name); 291 err = -ENODEV; 292 goto error_out; 293 } 294 if (count % 8 != 0) { 295 dev_err(&dev->dev, "Malformed interrupts property on %s\n", 296 dev->node->full_name); 297 err = -EINVAL; 298 goto error_out; 299 } 300 301 count /= sizeof(u32); 302 for (i = 0; i < count / 2; i++) { 303 if (i > NR_MSI_REG) 304 break; 305 virt_msir = irq_of_parse_and_map(dev->node, i); 306 if (virt_msir != NO_IRQ) { 307 set_irq_data(virt_msir, (void *)i); 308 set_irq_chained_handler(virt_msir, fsl_msi_cascade); 309 } 310 } 311 312 fsl_msi = msi; 313 314 WARN_ON(ppc_md.setup_msi_irqs); 315 ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; 316 ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs; 317 ppc_md.msi_check_device = fsl_msi_check_device; 318 return 0; 319 error_out: 320 kfree(msi); 321 return err; 322 } 323 324 static const struct fsl_msi_feature mpic_msi_feature = { 325 .fsl_pic_ip = FSL_PIC_IP_MPIC, 326 .msiir_offset = 0x140, 327 }; 328 329 static const struct fsl_msi_feature ipic_msi_feature = { 330 .fsl_pic_ip = FSL_PIC_IP_IPIC, 331 .msiir_offset = 0x38, 332 }; 333 334 static const struct of_device_id fsl_of_msi_ids[] = { 335 { 336 .compatible = "fsl,mpic-msi", 337 .data = (void *)&mpic_msi_feature, 338 }, 339 { 340 .compatible = "fsl,ipic-msi", 341 .data = (void *)&ipic_msi_feature, 342 }, 343 {} 344 }; 345 346 static struct of_platform_driver fsl_of_msi_driver = { 347 .name = "fsl-msi", 348 .match_table = fsl_of_msi_ids, 349 .probe = fsl_of_msi_probe, 350 }; 351 352 static __init int fsl_of_msi_init(void) 353 { 354 return of_register_platform_driver(&fsl_of_msi_driver); 355 } 356 357 subsys_initcall(fsl_of_msi_init); 358