Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Place interrupt related code into irq.c

Interrupt related code is spread into irq.c, pci.c, and setup-irq.c.
Group them into pre-existing irq.c.

Link: https://lore.kernel.org/r/20240129113655.3368-1-ilpo.jarvinen@linux.intel.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

authored by

Ilpo Järvinen and committed by
Bjorn Helgaas
1e8cc8e6 6613476e

+205 -218
+1 -1
drivers/pci/Makefile
··· 5 5 obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \ 6 6 remove.o pci.o pci-driver.o search.o \ 7 7 pci-sysfs.o rom.o setup-res.o irq.o vpd.o \ 8 - setup-bus.o vc.o mmap.o setup-irq.o 8 + setup-bus.o vc.o mmap.o 9 9 10 10 obj-$(CONFIG_PCI) += msi/ 11 11 obj-$(CONFIG_PCI) += pcie/
+204
drivers/pci/irq.c
··· 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> 15 + 16 + #include "pci.h" 13 17 14 18 /** 15 19 * pci_request_irq - allocate an interrupt line for a PCI device ··· 78 74 kfree(free_irq(pci_irq_vector(dev, nr), dev_id)); 79 75 } 80 76 EXPORT_SYMBOL(pci_free_irq); 77 + 78 + /** 79 + * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge 80 + * @dev: the PCI device 81 + * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) 82 + * 83 + * Perform INTx swizzling for a device behind one level of bridge. This is 84 + * required by section 9.1 of the PCI-to-PCI bridge specification for devices 85 + * behind bridges on add-in cards. For devices with ARI enabled, the slot 86 + * number is always 0 (see the Implementation Note in section 2.2.8.1 of 87 + * the PCI Express Base Specification, Revision 2.1) 88 + */ 89 + u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin) 90 + { 91 + int slot; 92 + 93 + if (pci_ari_enabled(dev->bus)) 94 + slot = 0; 95 + else 96 + slot = PCI_SLOT(dev->devfn); 97 + 98 + return (((pin - 1) + slot) % 4) + 1; 99 + } 100 + 101 + int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) 102 + { 103 + u8 pin; 104 + 105 + pin = dev->pin; 106 + if (!pin) 107 + return -1; 108 + 109 + while (!pci_is_root_bus(dev->bus)) { 110 + pin = pci_swizzle_interrupt_pin(dev, pin); 111 + dev = dev->bus->self; 112 + } 113 + *bridge = dev; 114 + return pin; 115 + } 116 + 117 + /** 118 + * pci_common_swizzle - swizzle INTx all the way to root bridge 119 + * @dev: the PCI device 120 + * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD) 121 + * 122 + * Perform INTx swizzling for a device. This traverses through all PCI-to-PCI 123 + * bridges all the way up to a PCI root bus. 124 + */ 125 + u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) 126 + { 127 + u8 pin = *pinp; 128 + 129 + while (!pci_is_root_bus(dev->bus)) { 130 + pin = pci_swizzle_interrupt_pin(dev, pin); 131 + dev = dev->bus->self; 132 + } 133 + *pinp = pin; 134 + return PCI_SLOT(dev->devfn); 135 + } 136 + EXPORT_SYMBOL_GPL(pci_common_swizzle); 137 + 138 + void pci_assign_irq(struct pci_dev *dev) 139 + { 140 + u8 pin; 141 + u8 slot = -1; 142 + int irq = 0; 143 + struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus); 144 + 145 + if (!(hbrg->map_irq)) { 146 + pci_dbg(dev, "runtime IRQ mapping not provided by arch\n"); 147 + return; 148 + } 149 + 150 + /* 151 + * If this device is not on the primary bus, we need to figure out 152 + * which interrupt pin it will come in on. We know which slot it 153 + * will come in on because that slot is where the bridge is. Each 154 + * time the interrupt line passes through a PCI-PCI bridge we must 155 + * apply the swizzle function. 156 + */ 157 + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); 158 + /* Cope with illegal. */ 159 + if (pin > 4) 160 + pin = 1; 161 + 162 + if (pin) { 163 + /* Follow the chain of bridges, swizzling as we go. */ 164 + if (hbrg->swizzle_irq) 165 + slot = (*(hbrg->swizzle_irq))(dev, &pin); 166 + 167 + /* 168 + * If a swizzling function is not used, map_irq() must 169 + * ignore slot. 170 + */ 171 + irq = (*(hbrg->map_irq))(dev, slot, pin); 172 + if (irq == -1) 173 + irq = 0; 174 + } 175 + dev->irq = irq; 176 + 177 + pci_dbg(dev, "assign IRQ: got %d\n", dev->irq); 178 + 179 + /* 180 + * Always tell the device, so the driver knows what is the real IRQ 181 + * to use; the device does not use it. 182 + */ 183 + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); 184 + } 185 + 186 + static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask) 187 + { 188 + struct pci_bus *bus = dev->bus; 189 + bool mask_updated = true; 190 + u32 cmd_status_dword; 191 + u16 origcmd, newcmd; 192 + unsigned long flags; 193 + bool irq_pending; 194 + 195 + /* 196 + * We do a single dword read to retrieve both command and status. 197 + * Document assumptions that make this possible. 198 + */ 199 + BUILD_BUG_ON(PCI_COMMAND % 4); 200 + BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); 201 + 202 + raw_spin_lock_irqsave(&pci_lock, flags); 203 + 204 + bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword); 205 + 206 + irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT; 207 + 208 + /* 209 + * Check interrupt status register to see whether our device 210 + * triggered the interrupt (when masking) or the next IRQ is 211 + * already pending (when unmasking). 212 + */ 213 + if (mask != irq_pending) { 214 + mask_updated = false; 215 + goto done; 216 + } 217 + 218 + origcmd = cmd_status_dword; 219 + newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE; 220 + if (mask) 221 + newcmd |= PCI_COMMAND_INTX_DISABLE; 222 + if (newcmd != origcmd) 223 + bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd); 224 + 225 + done: 226 + raw_spin_unlock_irqrestore(&pci_lock, flags); 227 + 228 + return mask_updated; 229 + } 230 + 231 + /** 232 + * pci_check_and_mask_intx - mask INTx on pending interrupt 233 + * @dev: the PCI device to operate on 234 + * 235 + * Check if the device dev has its INTx line asserted, mask it and return 236 + * true in that case. False is returned if no interrupt was pending. 237 + */ 238 + bool pci_check_and_mask_intx(struct pci_dev *dev) 239 + { 240 + return pci_check_and_set_intx_mask(dev, true); 241 + } 242 + EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); 243 + 244 + /** 245 + * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending 246 + * @dev: the PCI device to operate on 247 + * 248 + * Check if the device dev has its INTx line asserted, unmask it if not and 249 + * return true. False is returned and the mask remains active if there was 250 + * still an interrupt pending. 251 + */ 252 + bool pci_check_and_unmask_intx(struct pci_dev *dev) 253 + { 254 + return pci_check_and_set_intx_mask(dev, false); 255 + } 256 + EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); 257 + 258 + /** 259 + * pcibios_penalize_isa_irq - penalize an ISA IRQ 260 + * @irq: ISA IRQ to penalize 261 + * @active: IRQ active or not 262 + * 263 + * Permits the platform to provide architecture-specific functionality when 264 + * penalizing ISA IRQs. This is the default implementation. Architecture 265 + * implementations can override this. 266 + */ 267 + void __weak pcibios_penalize_isa_irq(int irq, int active) {} 268 + 269 + int __weak pcibios_alloc_irq(struct pci_dev *dev) 270 + { 271 + return 0; 272 + } 273 + 274 + void __weak pcibios_free_irq(struct pci_dev *dev) 275 + { 276 + }
-9
drivers/pci/pci-driver.c
··· 419 419 return error; 420 420 } 421 421 422 - int __weak pcibios_alloc_irq(struct pci_dev *dev) 423 - { 424 - return 0; 425 - } 426 - 427 - void __weak pcibios_free_irq(struct pci_dev *dev) 428 - { 429 - } 430 - 431 422 #ifdef CONFIG_PCI_IOV 432 423 static inline bool pci_device_can_probe(struct pci_dev *pdev) 433 424 {
-144
drivers/pci/pci.c
··· 24 24 #include <linux/log2.h> 25 25 #include <linux/logic_pio.h> 26 26 #include <linux/pm_wakeup.h> 27 - #include <linux/interrupt.h> 28 27 #include <linux/device.h> 29 28 #include <linux/pm_runtime.h> 30 29 #include <linux/pci_hotplug.h> ··· 2291 2292 */ 2292 2293 void __weak pcibios_disable_device(struct pci_dev *dev) {} 2293 2294 2294 - /** 2295 - * pcibios_penalize_isa_irq - penalize an ISA IRQ 2296 - * @irq: ISA IRQ to penalize 2297 - * @active: IRQ active or not 2298 - * 2299 - * Permits the platform to provide architecture-specific functionality when 2300 - * penalizing ISA IRQs. This is the default implementation. Architecture 2301 - * implementations can override this. 2302 - */ 2303 - void __weak pcibios_penalize_isa_irq(int irq, int active) {} 2304 - 2305 2295 static void do_pci_disable_device(struct pci_dev *dev) 2306 2296 { 2307 2297 u16 pci_command; ··· 3953 3965 EXPORT_SYMBOL(pci_enable_atomic_ops_to_root); 3954 3966 3955 3967 /** 3956 - * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge 3957 - * @dev: the PCI device 3958 - * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) 3959 - * 3960 - * Perform INTx swizzling for a device behind one level of bridge. This is 3961 - * required by section 9.1 of the PCI-to-PCI bridge specification for devices 3962 - * behind bridges on add-in cards. For devices with ARI enabled, the slot 3963 - * number is always 0 (see the Implementation Note in section 2.2.8.1 of 3964 - * the PCI Express Base Specification, Revision 2.1) 3965 - */ 3966 - u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin) 3967 - { 3968 - int slot; 3969 - 3970 - if (pci_ari_enabled(dev->bus)) 3971 - slot = 0; 3972 - else 3973 - slot = PCI_SLOT(dev->devfn); 3974 - 3975 - return (((pin - 1) + slot) % 4) + 1; 3976 - } 3977 - 3978 - int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) 3979 - { 3980 - u8 pin; 3981 - 3982 - pin = dev->pin; 3983 - if (!pin) 3984 - return -1; 3985 - 3986 - while (!pci_is_root_bus(dev->bus)) { 3987 - pin = pci_swizzle_interrupt_pin(dev, pin); 3988 - dev = dev->bus->self; 3989 - } 3990 - *bridge = dev; 3991 - return pin; 3992 - } 3993 - 3994 - /** 3995 - * pci_common_swizzle - swizzle INTx all the way to root bridge 3996 - * @dev: the PCI device 3997 - * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD) 3998 - * 3999 - * Perform INTx swizzling for a device. This traverses through all PCI-to-PCI 4000 - * bridges all the way up to a PCI root bus. 4001 - */ 4002 - u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) 4003 - { 4004 - u8 pin = *pinp; 4005 - 4006 - while (!pci_is_root_bus(dev->bus)) { 4007 - pin = pci_swizzle_interrupt_pin(dev, pin); 4008 - dev = dev->bus->self; 4009 - } 4010 - *pinp = pin; 4011 - return PCI_SLOT(dev->devfn); 4012 - } 4013 - EXPORT_SYMBOL_GPL(pci_common_swizzle); 4014 - 4015 - /** 4016 3968 * pci_release_region - Release a PCI bar 4017 3969 * @pdev: PCI device whose resources were previously reserved by 4018 3970 * pci_request_region() ··· 4664 4736 } 4665 4737 } 4666 4738 EXPORT_SYMBOL_GPL(pci_intx); 4667 - 4668 - static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask) 4669 - { 4670 - struct pci_bus *bus = dev->bus; 4671 - bool mask_updated = true; 4672 - u32 cmd_status_dword; 4673 - u16 origcmd, newcmd; 4674 - unsigned long flags; 4675 - bool irq_pending; 4676 - 4677 - /* 4678 - * We do a single dword read to retrieve both command and status. 4679 - * Document assumptions that make this possible. 4680 - */ 4681 - BUILD_BUG_ON(PCI_COMMAND % 4); 4682 - BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); 4683 - 4684 - raw_spin_lock_irqsave(&pci_lock, flags); 4685 - 4686 - bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword); 4687 - 4688 - irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT; 4689 - 4690 - /* 4691 - * Check interrupt status register to see whether our device 4692 - * triggered the interrupt (when masking) or the next IRQ is 4693 - * already pending (when unmasking). 4694 - */ 4695 - if (mask != irq_pending) { 4696 - mask_updated = false; 4697 - goto done; 4698 - } 4699 - 4700 - origcmd = cmd_status_dword; 4701 - newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE; 4702 - if (mask) 4703 - newcmd |= PCI_COMMAND_INTX_DISABLE; 4704 - if (newcmd != origcmd) 4705 - bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd); 4706 - 4707 - done: 4708 - raw_spin_unlock_irqrestore(&pci_lock, flags); 4709 - 4710 - return mask_updated; 4711 - } 4712 - 4713 - /** 4714 - * pci_check_and_mask_intx - mask INTx on pending interrupt 4715 - * @dev: the PCI device to operate on 4716 - * 4717 - * Check if the device dev has its INTx line asserted, mask it and return 4718 - * true in that case. False is returned if no interrupt was pending. 4719 - */ 4720 - bool pci_check_and_mask_intx(struct pci_dev *dev) 4721 - { 4722 - return pci_check_and_set_intx_mask(dev, true); 4723 - } 4724 - EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); 4725 - 4726 - /** 4727 - * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending 4728 - * @dev: the PCI device to operate on 4729 - * 4730 - * Check if the device dev has its INTx line asserted, unmask it if not and 4731 - * return true. False is returned and the mask remains active if there was 4732 - * still an interrupt pending. 4733 - */ 4734 - bool pci_check_and_unmask_intx(struct pci_dev *dev) 4735 - { 4736 - return pci_check_and_set_intx_mask(dev, false); 4737 - } 4738 - EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); 4739 4739 4740 4740 /** 4741 4741 * pci_wait_for_pending_transaction - wait for pending transaction
-64
drivers/pci/setup-irq.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Support routines for initializing a PCI subsystem 4 - * 5 - * Extruded from code written by 6 - * Dave Rusling (david.rusling@reo.mts.dec.com) 7 - * David Mosberger (davidm@cs.arizona.edu) 8 - * David Miller (davem@redhat.com) 9 - */ 10 - 11 - #include <linux/kernel.h> 12 - #include <linux/pci.h> 13 - #include <linux/errno.h> 14 - #include <linux/ioport.h> 15 - #include <linux/cache.h> 16 - #include "pci.h" 17 - 18 - void pci_assign_irq(struct pci_dev *dev) 19 - { 20 - u8 pin; 21 - u8 slot = -1; 22 - int irq = 0; 23 - struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus); 24 - 25 - if (!(hbrg->map_irq)) { 26 - pci_dbg(dev, "runtime IRQ mapping not provided by arch\n"); 27 - return; 28 - } 29 - 30 - /* 31 - * If this device is not on the primary bus, we need to figure out 32 - * which interrupt pin it will come in on. We know which slot it 33 - * will come in on because that slot is where the bridge is. Each 34 - * time the interrupt line passes through a PCI-PCI bridge we must 35 - * apply the swizzle function. 36 - */ 37 - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); 38 - /* Cope with illegal. */ 39 - if (pin > 4) 40 - pin = 1; 41 - 42 - if (pin) { 43 - /* Follow the chain of bridges, swizzling as we go. */ 44 - if (hbrg->swizzle_irq) 45 - slot = (*(hbrg->swizzle_irq))(dev, &pin); 46 - 47 - /* 48 - * If a swizzling function is not used, map_irq() must 49 - * ignore slot. 50 - */ 51 - irq = (*(hbrg->map_irq))(dev, slot, pin); 52 - if (irq == -1) 53 - irq = 0; 54 - } 55 - dev->irq = irq; 56 - 57 - pci_dbg(dev, "assign IRQ: got %d\n", dev->irq); 58 - 59 - /* 60 - * Always tell the device, so the driver knows what is the real IRQ 61 - * to use; the device does not use it. 62 - */ 63 - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); 64 - }