aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pcie/portdrv_core.c41
-rw-r--r--include/linux/pcieport_if.h1
2 files changed, 29 insertions, 13 deletions
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 273e97619bce..265eba033a4a 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -43,7 +43,7 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
43{ 43{
44 struct pcie_port_data *port_data = pci_get_drvdata(dev); 44 struct pcie_port_data *port_data = pci_get_drvdata(dev);
45 int i, pos, nvec, status = -EINVAL; 45 int i, pos, nvec, status = -EINVAL;
46 int interrupt_mode = PCIE_PORT_INTx_MODE; 46 int interrupt_mode = PCIE_PORT_NO_IRQ;
47 47
48 /* Set INTx as default */ 48 /* Set INTx as default */
49 for (i = 0, nvec = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { 49 for (i = 0, nvec = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
@@ -51,7 +51,9 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
51 nvec++; 51 nvec++;
52 vectors[i] = dev->irq; 52 vectors[i] = dev->irq;
53 } 53 }
54 54 if (dev->pin)
55 interrupt_mode = PCIE_PORT_INTx_MODE;
56
55 /* Check MSI quirk */ 57 /* Check MSI quirk */
56 if (port_data->port_type == PCIE_RC_PORT && pcie_mch_quirk) 58 if (port_data->port_type == PCIE_RC_PORT && pcie_mch_quirk)
57 return interrupt_mode; 59 return interrupt_mode;
@@ -141,7 +143,7 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
141 dev->id.vendor = parent->vendor; 143 dev->id.vendor = parent->vendor;
142 dev->id.device = parent->device; 144 dev->id.device = parent->device;
143 dev->id.port_type = port_type; 145 dev->id.port_type = port_type;
144 dev->id.service_type = (1 << service_type); 146 dev->id.service_type = service_type;
145 147
146 /* Initialize generic device interface */ 148 /* Initialize generic device interface */
147 device = &dev->device; 149 device = &dev->device;
@@ -232,19 +234,32 @@ int pcie_port_device_register(struct pci_dev *dev)
232 /* Allocate child services if any */ 234 /* Allocate child services if any */
233 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { 235 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
234 struct pcie_device *child; 236 struct pcie_device *child;
237 int service = 1 << i;
235 238
236 if (capabilities & (1 << i)) { 239 if (!(capabilities & service))
237 child = alloc_pcie_device(dev, i, vectors[i]); 240 continue;
238 if (child) { 241
239 status = device_register(&child->device); 242 /*
240 if (status) { 243 * Don't use service devices that require interrupts if there is
241 kfree(child); 244 * no way to generate them.
242 continue; 245 */
243 } 246 if (irq_mode == PCIE_PORT_NO_IRQ
244 get_device(&child->device); 247 && service != PCIE_PORT_SERVICE_VC)
245 } 248 continue;
249
250 child = alloc_pcie_device(dev, service, vectors[i]);
251 if (!child)
252 continue;
253
254 status = device_register(&child->device);
255 if (status) {
256 kfree(child);
257 continue;
246 } 258 }
259
260 get_device(&child->device);
247 } 261 }
262
248 return 0; 263 return 0;
249} 264}
250 265
diff --git a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h
index 194409af1037..8e1ae1fd92f6 100644
--- a/include/linux/pcieport_if.h
+++ b/include/linux/pcieport_if.h
@@ -22,6 +22,7 @@
22#define PCIE_PORT_SERVICE_VC 8 /* Virtual Channel */ 22#define PCIE_PORT_SERVICE_VC 8 /* Virtual Channel */
23 23
24/* Root/Upstream/Downstream Port's Interrupt Mode */ 24/* Root/Upstream/Downstream Port's Interrupt Mode */
25#define PCIE_PORT_NO_IRQ (-1)
25#define PCIE_PORT_INTx_MODE 0 26#define PCIE_PORT_INTx_MODE 0
26#define PCIE_PORT_MSI_MODE 1 27#define PCIE_PORT_MSI_MODE 1
27#define PCIE_PORT_MSIX_MODE 2 28#define PCIE_PORT_MSIX_MODE 2