Skip to content

Commit 420b8c3

Browse files
committed
Merge branch 'pci/enumeration'
- Collect interrupt-related code in irq.c (Ilpo Järvinen) - Mark 3ware-9650SE Root Port Extended Tags as broken (Jörg Wedekind) * pci/enumeration: PCI: Mark 3ware-9650SE Root Port Extended Tags as broken PCI: Place interrupt related code into irq.c # Conflicts: # drivers/pci/Makefile
2 parents c6c411a + baf67ae commit 420b8c3

File tree

6 files changed

+206
-218
lines changed

6 files changed

+206
-218
lines changed

drivers/pci/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
66
remove.o pci.o pci-driver.o search.o \
77
pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
8-
setup-bus.o vc.o mmap.o setup-irq.o devres.o
8+
setup-bus.o vc.o mmap.o devres.o
99

1010
obj-$(CONFIG_PCI) += msi/
1111
obj-$(CONFIG_PCI) += pcie/

drivers/pci/irq.c

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88

99
#include <linux/device.h>
1010
#include <linux/kernel.h>
11+
#include <linux/errno.h>
1112
#include <linux/export.h>
13+
#include <linux/interrupt.h>
1214
#include <linux/pci.h>
1315

16+
#include "pci.h"
17+
1418
/**
1519
* pci_request_irq - allocate an interrupt line for a PCI device
1620
* @dev: PCI device to operate on
@@ -74,3 +78,203 @@ void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id)
7478
kfree(free_irq(pci_irq_vector(dev, nr), dev_id));
7579
}
7680
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+
}

drivers/pci/pci-driver.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -419,15 +419,6 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
419419
return error;
420420
}
421421

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-
431422
#ifdef CONFIG_PCI_IOV
432423
static inline bool pci_device_can_probe(struct pci_dev *pdev)
433424
{

0 commit comments

Comments
 (0)