aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2009-01-13 08:38:34 -0500
committerJesse Barnes <jbarnes@hobbes.lan>2009-03-19 22:29:20 -0400
commit1bf83e558cb29d163f4bc6decbc3800ecf4db195 (patch)
treeccbf5bc39973a438f69fbd39317ef49a974c76ad /drivers/pci/pcie
parente496b617b40f2abf6d49803f56aa1344ce1b9177 (diff)
PCI: PCIe portdrv: Use driver data to simplify code
PCI Express port driver extension, as defined by struct pcie_port_device_ext in portdrv.h, is allocated and initialized, but never used (it also is never freed). Extend it to hold the PCI Express port type as well as the port interrupt mode, change its name and use it to simplify the code in portdrv_core.c . Additionally, remove the redundant interrupt_mode member of struct pcie_device defined in include/linux/pcieport_if.h . Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r--drivers/pci/pcie/portdrv.h5
-rw-r--r--drivers/pci/pcie/portdrv_core.c95
2 files changed, 39 insertions, 61 deletions
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 2529f3f2ea5a..b0dcbc73415e 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 8b3f8c18032f..273e97619bce 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/**