aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pcie/portdrv.h5
-rw-r--r--drivers/pci/pcie/portdrv_core.c95
-rw-r--r--include/linux/pcieport_if.h1
3 files changed, 39 insertions, 62 deletions
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 2529f3f2ea5..b0dcbc73415 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -28,8 +28,9 @@
28 28
29#define get_descriptor_id(type, service) (((type - 4) << 4) | service) 29#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
30 30
31struct pcie_port_device_ext { 31struct pcie_port_data {
32 int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */ 32 int port_type; /* Type of the port */
33 int port_irq_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */
33}; 34};
34 35
35extern struct bus_type pcie_port_bus_type; 36extern struct bus_type pcie_port_bus_type;
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 8b3f8c18032..273e97619bc 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -15,10 +15,9 @@
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <linux/pcieport_if.h> 16#include <linux/pcieport_if.h>
17 17
18#include "../pci.h"
18#include "portdrv.h" 19#include "portdrv.h"
19 20
20extern int pcie_mch_quirk; /* MSI-quirk Indicator */
21
22/** 21/**
23 * release_pcie_device - free PCI Express port service device structure 22 * release_pcie_device - free PCI Express port service device structure
24 * @dev: Port service device to release 23 * @dev: Port service device to release
@@ -31,28 +30,6 @@ static void release_pcie_device(struct device *dev)
31 kfree(to_pcie_device(dev)); 30 kfree(to_pcie_device(dev));
32} 31}
33 32
34static int is_msi_quirked(struct pci_dev *dev)
35{
36 int port_type, quirk = 0;
37 u16 reg16;
38
39 pci_read_config_word(dev,
40 pci_find_capability(dev, PCI_CAP_ID_EXP) +
41 PCIE_CAPABILITIES_REG, &reg16);
42 port_type = (reg16 >> 4) & PORT_TYPE_MASK;
43 switch(port_type) {
44 case PCIE_RC_PORT:
45 if (pcie_mch_quirk == 1)
46 quirk = 1;
47 break;
48 case PCIE_SW_UPSTREAM_PORT:
49 case PCIE_SW_DOWNSTREAM_PORT:
50 default:
51 break;
52 }
53 return quirk;
54}
55
56/** 33/**
57 * assign_interrupt_mode - choose interrupt mode for PCI Express port services 34 * assign_interrupt_mode - choose interrupt mode for PCI Express port services
58 * (INTx, MSI-X, MSI) and set up vectors 35 * (INTx, MSI-X, MSI) and set up vectors
@@ -64,6 +41,7 @@ static int is_msi_quirked(struct pci_dev *dev)
64 */ 41 */
65static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) 42static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
66{ 43{
44 struct pcie_port_data *port_data = pci_get_drvdata(dev);
67 int i, pos, nvec, status = -EINVAL; 45 int i, pos, nvec, status = -EINVAL;
68 int interrupt_mode = PCIE_PORT_INTx_MODE; 46 int interrupt_mode = PCIE_PORT_INTx_MODE;
69 47
@@ -75,7 +53,7 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
75 } 53 }
76 54
77 /* Check MSI quirk */ 55 /* Check MSI quirk */
78 if (is_msi_quirked(dev)) 56 if (port_data->port_type == PCIE_RC_PORT && pcie_mch_quirk)
79 return interrupt_mode; 57 return interrupt_mode;
80 58
81 /* Select MSI-X over MSI if supported */ 59 /* Select MSI-X over MSI if supported */
@@ -132,13 +110,11 @@ static int get_port_device_capability(struct pci_dev *dev)
132 pos + PCIE_SLOT_CAPABILITIES_REG, &reg32); 110 pos + PCIE_SLOT_CAPABILITIES_REG, &reg32);
133 if (reg32 & SLOT_HP_CAPABLE_MASK) 111 if (reg32 & SLOT_HP_CAPABLE_MASK)
134 services |= PCIE_PORT_SERVICE_HP; 112 services |= PCIE_PORT_SERVICE_HP;
135 } 113 }
136 /* PME Capable - root port capability */ 114 /* AER capable */
137 if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT)
138 services |= PCIE_PORT_SERVICE_PME;
139
140 if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) 115 if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR))
141 services |= PCIE_PORT_SERVICE_AER; 116 services |= PCIE_PORT_SERVICE_AER;
117 /* VC support */
142 if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) 118 if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
143 services |= PCIE_PORT_SERVICE_VC; 119 services |= PCIE_PORT_SERVICE_VC;
144 120
@@ -152,15 +128,15 @@ static int get_port_device_capability(struct pci_dev *dev)
152 * @port_type: Type of the port 128 * @port_type: Type of the port
153 * @service_type: Type of service to associate with the service device 129 * @service_type: Type of service to associate with the service device
154 * @irq: Interrupt vector to associate with the service device 130 * @irq: Interrupt vector to associate with the service device
155 * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI)
156 */ 131 */
157static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, 132static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
158 int port_type, int service_type, int irq, int irq_mode) 133 int service_type, int irq)
159{ 134{
135 struct pcie_port_data *port_data = pci_get_drvdata(parent);
160 struct device *device; 136 struct device *device;
137 int port_type = port_data->port_type;
161 138
162 dev->port = parent; 139 dev->port = parent;
163 dev->interrupt_mode = irq_mode;
164 dev->irq = irq; 140 dev->irq = irq;
165 dev->id.vendor = parent->vendor; 141 dev->id.vendor = parent->vendor;
166 dev->id.device = parent->device; 142 dev->id.device = parent->device;
@@ -185,10 +161,9 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
185 * @port_type: Type of the port 161 * @port_type: Type of the port
186 * @service_type: Type of service to associate with the service device 162 * @service_type: Type of service to associate with the service device
187 * @irq: Interrupt vector to associate with the service device 163 * @irq: Interrupt vector to associate with the service device
188 * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI)
189 */ 164 */
190static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, 165static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
191 int port_type, int service_type, int irq, int irq_mode) 166 int service_type, int irq)
192{ 167{
193 struct pcie_device *device; 168 struct pcie_device *device;
194 169
@@ -196,7 +171,7 @@ static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
196 if (!device) 171 if (!device)
197 return NULL; 172 return NULL;
198 173
199 pcie_device_init(parent, device, port_type, service_type, irq,irq_mode); 174 pcie_device_init(parent, device, service_type, irq);
200 return device; 175 return device;
201} 176}
202 177
@@ -230,39 +205,36 @@ int pcie_port_device_probe(struct pci_dev *dev)
230 */ 205 */
231int pcie_port_device_register(struct pci_dev *dev) 206int pcie_port_device_register(struct pci_dev *dev)
232{ 207{
233 struct pcie_port_device_ext *p_ext; 208 struct pcie_port_data *port_data;
234 int status, type, capabilities, irq_mode, i; 209 int status, capabilities, irq_mode, i;
235 int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; 210 int vectors[PCIE_PORT_DEVICE_MAXSERVICES];
236 u16 reg16; 211 u16 reg16;
237 212
238 /* Allocate port device extension */ 213 port_data = kzalloc(sizeof(*port_data), GFP_KERNEL);
239 if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL))) 214 if (!port_data)
240 return -ENOMEM; 215 return -ENOMEM;
241 216 pci_set_drvdata(dev, port_data);
242 pci_set_drvdata(dev, p_ext);
243 217
244 /* Get port type */ 218 /* Get port type */
245 pci_read_config_word(dev, 219 pci_read_config_word(dev,
246 pci_find_capability(dev, PCI_CAP_ID_EXP) + 220 pci_find_capability(dev, PCI_CAP_ID_EXP) +
247 PCIE_CAPABILITIES_REG, &reg16); 221 PCIE_CAPABILITIES_REG, &reg16);
248 type = (reg16 >> 4) & PORT_TYPE_MASK; 222 port_data->port_type = (reg16 >> 4) & PORT_TYPE_MASK;
249 223
250 /* Now get port services */
251 capabilities = get_port_device_capability(dev); 224 capabilities = get_port_device_capability(dev);
225 /* Root ports are capable of generating PME too */
226 if (port_data->port_type == PCIE_RC_PORT)
227 capabilities |= PCIE_PORT_SERVICE_PME;
228
252 irq_mode = assign_interrupt_mode(dev, vectors, capabilities); 229 irq_mode = assign_interrupt_mode(dev, vectors, capabilities);
253 p_ext->interrupt_mode = irq_mode; 230 port_data->port_irq_mode = irq_mode;
254 231
255 /* Allocate child services if any */ 232 /* Allocate child services if any */
256 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { 233 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
257 struct pcie_device *child; 234 struct pcie_device *child;
258 235
259 if (capabilities & (1 << i)) { 236 if (capabilities & (1 << i)) {
260 child = alloc_pcie_device( 237 child = alloc_pcie_device(dev, i, vectors[i]);
261 dev, /* parent */
262 type, /* port type */
263 i, /* service type */
264 vectors[i], /* irq */
265 irq_mode /* interrupt mode */);
266 if (child) { 238 if (child) {
267 status = device_register(&child->device); 239 status = device_register(&child->device);
268 if (status) { 240 if (status) {
@@ -349,25 +321,30 @@ static int remove_iter(struct device *dev, void *data)
349 */ 321 */
350void pcie_port_device_remove(struct pci_dev *dev) 322void pcie_port_device_remove(struct pci_dev *dev)
351{ 323{
352 struct device *device; 324 struct pcie_port_data *port_data = pci_get_drvdata(dev);
353 unsigned long device_addr;
354 int interrupt_mode = PCIE_PORT_INTx_MODE;
355 int status; 325 int status;
356 326
357 do { 327 do {
328 unsigned long device_addr;
329
358 status = device_for_each_child(&dev->dev, &device_addr, remove_iter); 330 status = device_for_each_child(&dev->dev, &device_addr, remove_iter);
359 if (status) { 331 if (status) {
360 device = (struct device*)device_addr; 332 struct device *device = (struct device*)device_addr;
361 interrupt_mode = (to_pcie_device(device))->interrupt_mode;
362 put_device(device); 333 put_device(device);
363 device_unregister(device); 334 device_unregister(device);
364 } 335 }
365 } while (status); 336 } while (status);
366 /* Switch to INTx by default if MSI enabled */ 337
367 if (interrupt_mode == PCIE_PORT_MSIX_MODE) 338 switch (port_data->port_irq_mode) {
339 case PCIE_PORT_MSIX_MODE:
368 pci_disable_msix(dev); 340 pci_disable_msix(dev);
369 else if (interrupt_mode == PCIE_PORT_MSI_MODE) 341 break;
342 case PCIE_PORT_MSI_MODE:
370 pci_disable_msi(dev); 343 pci_disable_msi(dev);
344 break;
345 }
346
347 kfree(port_data);
371} 348}
372 349
373/** 350/**
diff --git a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h
index 6cd91e3f982..194409af103 100644
--- a/include/linux/pcieport_if.h
+++ b/include/linux/pcieport_if.h
@@ -36,7 +36,6 @@ struct pcie_port_service_id {
36 36
37struct pcie_device { 37struct pcie_device {
38 int irq; /* Service IRQ/MSI/MSI-X Vector */ 38 int irq; /* Service IRQ/MSI/MSI-X Vector */
39 int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */
40 struct pcie_port_service_id id; /* Service ID */ 39 struct pcie_port_service_id id; /* Service ID */
41 struct pci_dev *port; /* Root/Upstream/Downstream Port */ 40 struct pci_dev *port; /* Root/Upstream/Downstream Port */
42 void *priv_data; /* Service Private Data */ 41 void *priv_data; /* Service Private Data */