• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * File:	portdrv_pci.c
3  * Purpose:	PCI Express Port Bus Driver
4  *
5  * Copyright (C) 2004 Intel
6  * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
7  */
8 
9 #include <linux/module.h>
10 #include <linux/pci.h>
11 #include <linux/kernel.h>
12 #include <linux/errno.h>
13 #include <linux/pm.h>
14 #include <linux/init.h>
15 #include <linux/slab.h>
16 #include <linux/pcieport_if.h>
17 #include <linux/aer.h>
18 
19 #include "portdrv.h"
20 #include "aer/aerdrv.h"
21 
22 /*
23  * Version Information
24  */
25 #define DRIVER_VERSION "v1.0"
26 #define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
27 #define DRIVER_DESC "PCIE Port Bus Driver"
28 MODULE_AUTHOR(DRIVER_AUTHOR);
29 MODULE_DESCRIPTION(DRIVER_DESC);
30 MODULE_LICENSE("GPL");
31 
32 /* global data */
33 static const char device_name[] = "pcieport-driver";
34 
pcie_portdrv_save_config(struct pci_dev * dev)35 static int pcie_portdrv_save_config(struct pci_dev *dev)
36 {
37 	return pci_save_state(dev);
38 }
39 
pcie_portdrv_restore_config(struct pci_dev * dev)40 static int pcie_portdrv_restore_config(struct pci_dev *dev)
41 {
42 	int retval;
43 
44 	retval = pci_enable_device(dev);
45 	if (retval)
46 		return retval;
47 	pci_set_master(dev);
48 	return 0;
49 }
50 
51 #ifdef CONFIG_PM
pcie_portdrv_suspend(struct pci_dev * dev,pm_message_t state)52 static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
53 {
54 	return pcie_port_device_suspend(dev, state);
55 
56 }
57 
pcie_portdrv_resume(struct pci_dev * dev)58 static int pcie_portdrv_resume(struct pci_dev *dev)
59 {
60 	pci_set_master(dev);
61 	return pcie_port_device_resume(dev);
62 }
63 #else
64 #define pcie_portdrv_suspend NULL
65 #define pcie_portdrv_resume NULL
66 #endif
67 
68 /*
69  * pcie_portdrv_probe - Probe PCI-Express port devices
70  * @dev: PCI-Express port device being probed
71  *
72  * If detected invokes the pcie_port_device_register() method for
73  * this port device.
74  *
75  */
pcie_portdrv_probe(struct pci_dev * dev,const struct pci_device_id * id)76 static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
77 				const struct pci_device_id *id )
78 {
79 	int			status;
80 
81 	status = pcie_port_device_probe(dev);
82 	if (status)
83 		return status;
84 
85 	if (pci_enable_device(dev) < 0)
86 		return -ENODEV;
87 
88 	pci_set_master(dev);
89         if (!dev->irq && dev->pin) {
90 		dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; "
91 			 "check vendor BIOS\n", dev->vendor, dev->device);
92 	}
93 	if (pcie_port_device_register(dev)) {
94 		pci_disable_device(dev);
95 		return -ENOMEM;
96 	}
97 
98 	pcie_portdrv_save_config(dev);
99 
100 	return 0;
101 }
102 
pcie_portdrv_remove(struct pci_dev * dev)103 static void pcie_portdrv_remove (struct pci_dev *dev)
104 {
105 	pcie_port_device_remove(dev);
106 	pci_disable_device(dev);
107 	kfree(pci_get_drvdata(dev));
108 }
109 
error_detected_iter(struct device * device,void * data)110 static int error_detected_iter(struct device *device, void *data)
111 {
112 	struct pcie_device *pcie_device;
113 	struct pcie_port_service_driver *driver;
114 	struct aer_broadcast_data *result_data;
115 	pci_ers_result_t status;
116 
117 	result_data = (struct aer_broadcast_data *) data;
118 
119 	if (device->bus == &pcie_port_bus_type && device->driver) {
120 		driver = to_service_driver(device->driver);
121 		if (!driver ||
122 			!driver->err_handler ||
123 			!driver->err_handler->error_detected)
124 			return 0;
125 
126 		pcie_device = to_pcie_device(device);
127 
128 		/* Forward error detected message to service drivers */
129 		status = driver->err_handler->error_detected(
130 			pcie_device->port,
131 			result_data->state);
132 		result_data->result =
133 			merge_result(result_data->result, status);
134 	}
135 
136 	return 0;
137 }
138 
pcie_portdrv_error_detected(struct pci_dev * dev,enum pci_channel_state error)139 static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
140 					enum pci_channel_state error)
141 {
142 	struct aer_broadcast_data result_data =
143 			{error, PCI_ERS_RESULT_CAN_RECOVER};
144 	int retval;
145 
146 	/* can not fail */
147 	retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter);
148 
149 	return result_data.result;
150 }
151 
mmio_enabled_iter(struct device * device,void * data)152 static int mmio_enabled_iter(struct device *device, void *data)
153 {
154 	struct pcie_device *pcie_device;
155 	struct pcie_port_service_driver *driver;
156 	pci_ers_result_t status, *result;
157 
158 	result = (pci_ers_result_t *) data;
159 
160 	if (device->bus == &pcie_port_bus_type && device->driver) {
161 		driver = to_service_driver(device->driver);
162 		if (driver &&
163 			driver->err_handler &&
164 			driver->err_handler->mmio_enabled) {
165 			pcie_device = to_pcie_device(device);
166 
167 			/* Forward error message to service drivers */
168 			status = driver->err_handler->mmio_enabled(
169 					pcie_device->port);
170 			*result = merge_result(*result, status);
171 		}
172 	}
173 
174 	return 0;
175 }
176 
pcie_portdrv_mmio_enabled(struct pci_dev * dev)177 static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
178 {
179 	pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
180 	int retval;
181 
182 	/* get true return value from &status */
183 	retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
184 	return status;
185 }
186 
slot_reset_iter(struct device * device,void * data)187 static int slot_reset_iter(struct device *device, void *data)
188 {
189 	struct pcie_device *pcie_device;
190 	struct pcie_port_service_driver *driver;
191 	pci_ers_result_t status, *result;
192 
193 	result = (pci_ers_result_t *) data;
194 
195 	if (device->bus == &pcie_port_bus_type && device->driver) {
196 		driver = to_service_driver(device->driver);
197 		if (driver &&
198 			driver->err_handler &&
199 			driver->err_handler->slot_reset) {
200 			pcie_device = to_pcie_device(device);
201 
202 			/* Forward error message to service drivers */
203 			status = driver->err_handler->slot_reset(
204 					pcie_device->port);
205 			*result = merge_result(*result, status);
206 		}
207 	}
208 
209 	return 0;
210 }
211 
pcie_portdrv_slot_reset(struct pci_dev * dev)212 static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
213 {
214 	pci_ers_result_t status = PCI_ERS_RESULT_NONE;
215 	int retval;
216 
217 	/* If fatal, restore cfg space for possible link reset at upstream */
218 	if (dev->error_state == pci_channel_io_frozen) {
219 		pci_restore_state(dev);
220 		pcie_portdrv_restore_config(dev);
221 		pci_enable_pcie_error_reporting(dev);
222 	}
223 
224 	/* get true return value from &status */
225 	retval = device_for_each_child(&dev->dev, &status, slot_reset_iter);
226 
227 	return status;
228 }
229 
resume_iter(struct device * device,void * data)230 static int resume_iter(struct device *device, void *data)
231 {
232 	struct pcie_device *pcie_device;
233 	struct pcie_port_service_driver *driver;
234 
235 	if (device->bus == &pcie_port_bus_type && device->driver) {
236 		driver = to_service_driver(device->driver);
237 		if (driver &&
238 			driver->err_handler &&
239 			driver->err_handler->resume) {
240 			pcie_device = to_pcie_device(device);
241 
242 			/* Forward error message to service drivers */
243 			driver->err_handler->resume(pcie_device->port);
244 		}
245 	}
246 
247 	return 0;
248 }
249 
pcie_portdrv_err_resume(struct pci_dev * dev)250 static void pcie_portdrv_err_resume(struct pci_dev *dev)
251 {
252 	int retval;
253 	/* nothing to do with error value, if it ever happens */
254 	retval = device_for_each_child(&dev->dev, NULL, resume_iter);
255 }
256 
257 /*
258  * LINUX Device Driver Model
259  */
260 static const struct pci_device_id port_pci_ids[] = { {
261 	/* handle any PCI-Express port */
262 	PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0),
263 	}, { /* end: all zeroes */ }
264 };
265 MODULE_DEVICE_TABLE(pci, port_pci_ids);
266 
267 static struct pci_error_handlers pcie_portdrv_err_handler = {
268 		.error_detected = pcie_portdrv_error_detected,
269 		.mmio_enabled = pcie_portdrv_mmio_enabled,
270 		.slot_reset = pcie_portdrv_slot_reset,
271 		.resume = pcie_portdrv_err_resume,
272 };
273 
274 static struct pci_driver pcie_portdriver = {
275 	.name		= (char *)device_name,
276 	.id_table	= &port_pci_ids[0],
277 
278 	.probe		= pcie_portdrv_probe,
279 	.remove		= pcie_portdrv_remove,
280 
281 	.suspend	= pcie_portdrv_suspend,
282 	.resume		= pcie_portdrv_resume,
283 
284 	.err_handler 	= &pcie_portdrv_err_handler,
285 };
286 
pcie_portdrv_init(void)287 static int __init pcie_portdrv_init(void)
288 {
289 	int retval;
290 
291 	retval = pcie_port_bus_register();
292 	if (retval) {
293 		printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval);
294 		goto out;
295 	}
296 	retval = pci_register_driver(&pcie_portdriver);
297 	if (retval)
298 		pcie_port_bus_unregister();
299  out:
300 	return retval;
301 }
302 
pcie_portdrv_exit(void)303 static void __exit pcie_portdrv_exit(void)
304 {
305 	pci_unregister_driver(&pcie_portdriver);
306 	pcie_port_bus_unregister();
307 }
308 
309 module_init(pcie_portdrv_init);
310 module_exit(pcie_portdrv_exit);
311