|
8 | 8 |
|
9 | 9 | #include <linux/device.h>
|
10 | 10 | #include <linux/kernel.h>
|
| 11 | +#include <linux/errno.h> |
11 | 12 | #include <linux/export.h>
|
| 13 | +#include <linux/interrupt.h> |
12 | 14 | #include <linux/pci.h>
|
13 | 15 |
|
| 16 | +#include "pci.h" |
| 17 | + |
14 | 18 | /**
|
15 | 19 | * pci_request_irq - allocate an interrupt line for a PCI device
|
16 | 20 | * @dev: PCI device to operate on
|
@@ -74,3 +78,203 @@ void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id)
|
74 | 78 | kfree(free_irq(pci_irq_vector(dev, nr), dev_id));
|
75 | 79 | }
|
76 | 80 | EXPORT_SYMBOL(pci_free_irq);
|
| 81 | + |
| 82 | +/** |
| 83 | + * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge |
| 84 | + * @dev: the PCI device |
| 85 | + * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) |
| 86 | + * |
| 87 | + * Perform INTx swizzling for a device behind one level of bridge. This is |
| 88 | + * required by section 9.1 of the PCI-to-PCI bridge specification for devices |
| 89 | + * behind bridges on add-in cards. For devices with ARI enabled, the slot |
| 90 | + * number is always 0 (see the Implementation Note in section 2.2.8.1 of |
| 91 | + * the PCI Express Base Specification, Revision 2.1) |
| 92 | + */ |
| 93 | +u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin) |
| 94 | +{ |
| 95 | + int slot; |
| 96 | + |
| 97 | + if (pci_ari_enabled(dev->bus)) |
| 98 | + slot = 0; |
| 99 | + else |
| 100 | + slot = PCI_SLOT(dev->devfn); |
| 101 | + |
| 102 | + return (((pin - 1) + slot) % 4) + 1; |
| 103 | +} |
| 104 | + |
| 105 | +int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) |
| 106 | +{ |
| 107 | + u8 pin; |
| 108 | + |
| 109 | + pin = dev->pin; |
| 110 | + if (!pin) |
| 111 | + return -1; |
| 112 | + |
| 113 | + while (!pci_is_root_bus(dev->bus)) { |
| 114 | + pin = pci_swizzle_interrupt_pin(dev, pin); |
| 115 | + dev = dev->bus->self; |
| 116 | + } |
| 117 | + *bridge = dev; |
| 118 | + return pin; |
| 119 | +} |
| 120 | + |
| 121 | +/** |
| 122 | + * pci_common_swizzle - swizzle INTx all the way to root bridge |
| 123 | + * @dev: the PCI device |
| 124 | + * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD) |
| 125 | + * |
| 126 | + * Perform INTx swizzling for a device. This traverses through all PCI-to-PCI |
| 127 | + * bridges all the way up to a PCI root bus. |
| 128 | + */ |
| 129 | +u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) |
| 130 | +{ |
| 131 | + u8 pin = *pinp; |
| 132 | + |
| 133 | + while (!pci_is_root_bus(dev->bus)) { |
| 134 | + pin = pci_swizzle_interrupt_pin(dev, pin); |
| 135 | + dev = dev->bus->self; |
| 136 | + } |
| 137 | + *pinp = pin; |
| 138 | + return PCI_SLOT(dev->devfn); |
| 139 | +} |
| 140 | +EXPORT_SYMBOL_GPL(pci_common_swizzle); |
| 141 | + |
| 142 | +void pci_assign_irq(struct pci_dev *dev) |
| 143 | +{ |
| 144 | + u8 pin; |
| 145 | + u8 slot = -1; |
| 146 | + int irq = 0; |
| 147 | + struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus); |
| 148 | + |
| 149 | + if (!(hbrg->map_irq)) { |
| 150 | + pci_dbg(dev, "runtime IRQ mapping not provided by arch\n"); |
| 151 | + return; |
| 152 | + } |
| 153 | + |
| 154 | + /* |
| 155 | + * If this device is not on the primary bus, we need to figure out |
| 156 | + * which interrupt pin it will come in on. We know which slot it |
| 157 | + * will come in on because that slot is where the bridge is. Each |
| 158 | + * time the interrupt line passes through a PCI-PCI bridge we must |
| 159 | + * apply the swizzle function. |
| 160 | + */ |
| 161 | + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); |
| 162 | + /* Cope with illegal. */ |
| 163 | + if (pin > 4) |
| 164 | + pin = 1; |
| 165 | + |
| 166 | + if (pin) { |
| 167 | + /* Follow the chain of bridges, swizzling as we go. */ |
| 168 | + if (hbrg->swizzle_irq) |
| 169 | + slot = (*(hbrg->swizzle_irq))(dev, &pin); |
| 170 | + |
| 171 | + /* |
| 172 | + * If a swizzling function is not used, map_irq() must |
| 173 | + * ignore slot. |
| 174 | + */ |
| 175 | + irq = (*(hbrg->map_irq))(dev, slot, pin); |
| 176 | + if (irq == -1) |
| 177 | + irq = 0; |
| 178 | + } |
| 179 | + dev->irq = irq; |
| 180 | + |
| 181 | + pci_dbg(dev, "assign IRQ: got %d\n", dev->irq); |
| 182 | + |
| 183 | + /* |
| 184 | + * Always tell the device, so the driver knows what is the real IRQ |
| 185 | + * to use; the device does not use it. |
| 186 | + */ |
| 187 | + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); |
| 188 | +} |
| 189 | + |
| 190 | +static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask) |
| 191 | +{ |
| 192 | + struct pci_bus *bus = dev->bus; |
| 193 | + bool mask_updated = true; |
| 194 | + u32 cmd_status_dword; |
| 195 | + u16 origcmd, newcmd; |
| 196 | + unsigned long flags; |
| 197 | + bool irq_pending; |
| 198 | + |
| 199 | + /* |
| 200 | + * We do a single dword read to retrieve both command and status. |
| 201 | + * Document assumptions that make this possible. |
| 202 | + */ |
| 203 | + BUILD_BUG_ON(PCI_COMMAND % 4); |
| 204 | + BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); |
| 205 | + |
| 206 | + raw_spin_lock_irqsave(&pci_lock, flags); |
| 207 | + |
| 208 | + bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword); |
| 209 | + |
| 210 | + irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT; |
| 211 | + |
| 212 | + /* |
| 213 | + * Check interrupt status register to see whether our device |
| 214 | + * triggered the interrupt (when masking) or the next IRQ is |
| 215 | + * already pending (when unmasking). |
| 216 | + */ |
| 217 | + if (mask != irq_pending) { |
| 218 | + mask_updated = false; |
| 219 | + goto done; |
| 220 | + } |
| 221 | + |
| 222 | + origcmd = cmd_status_dword; |
| 223 | + newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE; |
| 224 | + if (mask) |
| 225 | + newcmd |= PCI_COMMAND_INTX_DISABLE; |
| 226 | + if (newcmd != origcmd) |
| 227 | + bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd); |
| 228 | + |
| 229 | +done: |
| 230 | + raw_spin_unlock_irqrestore(&pci_lock, flags); |
| 231 | + |
| 232 | + return mask_updated; |
| 233 | +} |
| 234 | + |
| 235 | +/** |
| 236 | + * pci_check_and_mask_intx - mask INTx on pending interrupt |
| 237 | + * @dev: the PCI device to operate on |
| 238 | + * |
| 239 | + * Check if the device dev has its INTx line asserted, mask it and return |
| 240 | + * true in that case. False is returned if no interrupt was pending. |
| 241 | + */ |
| 242 | +bool pci_check_and_mask_intx(struct pci_dev *dev) |
| 243 | +{ |
| 244 | + return pci_check_and_set_intx_mask(dev, true); |
| 245 | +} |
| 246 | +EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); |
| 247 | + |
| 248 | +/** |
| 249 | + * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending |
| 250 | + * @dev: the PCI device to operate on |
| 251 | + * |
| 252 | + * Check if the device dev has its INTx line asserted, unmask it if not and |
| 253 | + * return true. False is returned and the mask remains active if there was |
| 254 | + * still an interrupt pending. |
| 255 | + */ |
| 256 | +bool pci_check_and_unmask_intx(struct pci_dev *dev) |
| 257 | +{ |
| 258 | + return pci_check_and_set_intx_mask(dev, false); |
| 259 | +} |
| 260 | +EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); |
| 261 | + |
| 262 | +/** |
| 263 | + * pcibios_penalize_isa_irq - penalize an ISA IRQ |
| 264 | + * @irq: ISA IRQ to penalize |
| 265 | + * @active: IRQ active or not |
| 266 | + * |
| 267 | + * Permits the platform to provide architecture-specific functionality when |
| 268 | + * penalizing ISA IRQs. This is the default implementation. Architecture |
| 269 | + * implementations can override this. |
| 270 | + */ |
| 271 | +void __weak pcibios_penalize_isa_irq(int irq, int active) {} |
| 272 | + |
| 273 | +int __weak pcibios_alloc_irq(struct pci_dev *dev) |
| 274 | +{ |
| 275 | + return 0; |
| 276 | +} |
| 277 | + |
| 278 | +void __weak pcibios_free_irq(struct pci_dev *dev) |
| 279 | +{ |
| 280 | +} |
0 commit comments