1 /* 2 * Copyright 2006, Segher Boessenkool, IBM Corporation. 3 * Copyright 2006-2007, Michael Ellerman, IBM Corporation. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; version 2 of the 8 * License. 9 * 10 */ 11 12 #include <linux/irq.h> 13 #include <linux/bootmem.h> 14 #include <linux/msi.h> 15 #include <asm/mpic.h> 16 #include <asm/prom.h> 17 #include <asm/hw_irq.h> 18 #include <asm/ppc-pci.h> 19 20 #include "mpic.h" 21 22 /* A bit ugly, can we get this from the pci_dev somehow? */ 23 static struct mpic *msi_mpic; 24 25 static void mpic_u3msi_mask_irq(unsigned int irq) 26 { 27 mask_msi_irq(irq); 28 mpic_mask_irq(irq); 29 } 30 31 static void mpic_u3msi_unmask_irq(unsigned int irq) 32 { 33 mpic_unmask_irq(irq); 34 unmask_msi_irq(irq); 35 } 36 37 static struct irq_chip mpic_u3msi_chip = { 38 .shutdown = mpic_u3msi_mask_irq, 39 .mask = mpic_u3msi_mask_irq, 40 .unmask = mpic_u3msi_unmask_irq, 41 .eoi = mpic_end_irq, 42 .set_type = mpic_set_irq_type, 43 .typename = "MPIC-U3MSI", 44 }; 45 46 static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos) 47 { 48 u8 flags; 49 u32 tmp; 50 u64 addr; 51 52 pci_read_config_byte(pdev, pos + HT_MSI_FLAGS, &flags); 53 54 if (flags & HT_MSI_FLAGS_FIXED) 55 return HT_MSI_FIXED_ADDR; 56 57 pci_read_config_dword(pdev, pos + HT_MSI_ADDR_LO, &tmp); 58 addr = tmp & HT_MSI_ADDR_LO_MASK; 59 pci_read_config_dword(pdev, pos + HT_MSI_ADDR_HI, &tmp); 60 addr = addr | ((u64)tmp << 32); 61 62 return addr; 63 } 64 65 static u64 find_ht_magic_addr(struct pci_dev *pdev) 66 { 67 struct pci_bus *bus; 68 unsigned int pos; 69 70 for (bus = pdev->bus; bus; bus = bus->parent) { 71 pos = pci_find_ht_capability(bus->self, HT_CAPTYPE_MSI_MAPPING); 72 if (pos) 73 return read_ht_magic_addr(bus->self, pos); 74 } 75 76 return 0; 77 } 78 79 static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type) 80 { 81 if (type == PCI_CAP_ID_MSIX) 82 pr_debug("u3msi: MSI-X untested, trying anyway.\n"); 83 84 /* If we can't find a magic address then MSI ain't gonna work */ 85 if (find_ht_magic_addr(pdev) == 0) { 86 pr_debug("u3msi: no magic address found for %s\n", 87 pci_name(pdev)); 88 return -ENXIO; 89 } 90 91 return 0; 92 } 93 94 static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) 95 { 96 struct msi_desc *entry; 97 98 list_for_each_entry(entry, &pdev->msi_list, list) { 99 if (entry->irq == NO_IRQ) 100 continue; 101 102 set_irq_msi(entry->irq, NULL); 103 mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1); 104 irq_dispose_mapping(entry->irq); 105 } 106 107 return; 108 } 109 110 static void u3msi_compose_msi_msg(struct pci_dev *pdev, int virq, 111 struct msi_msg *msg) 112 { 113 u64 addr; 114 115 addr = find_ht_magic_addr(pdev); 116 msg->address_lo = addr & 0xFFFFFFFF; 117 msg->address_hi = addr >> 32; 118 msg->data = virq_to_hw(virq); 119 120 pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) at address 0x%lx\n", 121 virq, virq_to_hw(virq), addr); 122 } 123 124 static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) 125 { 126 irq_hw_number_t hwirq; 127 int rc; 128 unsigned int virq; 129 struct msi_desc *entry; 130 struct msi_msg msg; 131 132 list_for_each_entry(entry, &pdev->msi_list, list) { 133 hwirq = mpic_msi_alloc_hwirqs(msi_mpic, 1); 134 if (hwirq < 0) { 135 rc = hwirq; 136 pr_debug("u3msi: failed allocating hwirq\n"); 137 goto out_free; 138 } 139 140 virq = irq_create_mapping(msi_mpic->irqhost, hwirq); 141 if (virq == NO_IRQ) { 142 pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq); 143 mpic_msi_free_hwirqs(msi_mpic, hwirq, 1); 144 rc = -ENOSPC; 145 goto out_free; 146 } 147 148 set_irq_msi(virq, entry); 149 set_irq_chip(virq, &mpic_u3msi_chip); 150 set_irq_type(virq, IRQ_TYPE_EDGE_RISING); 151 152 u3msi_compose_msi_msg(pdev, virq, &msg); 153 write_msi_msg(virq, &msg); 154 155 hwirq++; 156 } 157 158 return 0; 159 160 out_free: 161 u3msi_teardown_msi_irqs(pdev); 162 return rc; 163 } 164 165 int mpic_u3msi_init(struct mpic *mpic) 166 { 167 int rc; 168 169 rc = mpic_msi_init_allocator(mpic); 170 if (rc) { 171 pr_debug("u3msi: Error allocating bitmap!\n"); 172 return rc; 173 } 174 175 pr_debug("u3msi: Registering MPIC U3 MSI callbacks.\n"); 176 177 BUG_ON(msi_mpic); 178 msi_mpic = mpic; 179 180 WARN_ON(ppc_md.setup_msi_irqs); 181 ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs; 182 ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs; 183 ppc_md.msi_check_device = u3msi_msi_check_device; 184 185 return 0; 186 } 187