aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/cpci_hotplug_pci.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/pci/hotplug/cpci_hotplug_pci.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/pci/hotplug/cpci_hotplug_pci.c')
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c661
1 files changed, 661 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
new file mode 100644
index 000000000000..2e969616f298
--- /dev/null
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -0,0 +1,661 @@
1/*
2 * CompactPCI Hot Plug Driver PCI functions
3 *
4 * Copyright (C) 2002 by SOMA Networks, Inc.
5 *
6 * All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
16 * NON INFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * Send feedback to <scottm@somanetworks.com>
24 */
25
26#include <linux/config.h>
27#include <linux/module.h>
28#include <linux/kernel.h>
29#include <linux/pci.h>
30#include <linux/proc_fs.h>
31#include "../pci.h"
32#include "pci_hotplug.h"
33#include "cpci_hotplug.h"
34
35#if !defined(MODULE)
36#define MY_NAME "cpci_hotplug"
37#else
38#define MY_NAME THIS_MODULE->name
39#endif
40
41extern int cpci_debug;
42
43#define dbg(format, arg...) \
44 do { \
45 if(cpci_debug) \
46 printk (KERN_DEBUG "%s: " format "\n", \
47 MY_NAME , ## arg); \
48 } while(0)
49#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
50#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
51#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
52
53#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
54
55
56u8 cpci_get_attention_status(struct slot* slot)
57{
58 int hs_cap;
59 u16 hs_csr;
60
61 hs_cap = pci_bus_find_capability(slot->bus,
62 slot->devfn,
63 PCI_CAP_ID_CHSWP);
64 if(!hs_cap) {
65 return 0;
66 }
67
68 if(pci_bus_read_config_word(slot->bus,
69 slot->devfn,
70 hs_cap + 2,
71 &hs_csr)) {
72 return 0;
73 }
74 return hs_csr & 0x0008 ? 1 : 0;
75}
76
77int cpci_set_attention_status(struct slot* slot, int status)
78{
79 int hs_cap;
80 u16 hs_csr;
81
82 hs_cap = pci_bus_find_capability(slot->bus,
83 slot->devfn,
84 PCI_CAP_ID_CHSWP);
85 if(!hs_cap) {
86 return 0;
87 }
88
89 if(pci_bus_read_config_word(slot->bus,
90 slot->devfn,
91 hs_cap + 2,
92 &hs_csr)) {
93 return 0;
94 }
95 if(status) {
96 hs_csr |= HS_CSR_LOO;
97 } else {
98 hs_csr &= ~HS_CSR_LOO;
99 }
100 if(pci_bus_write_config_word(slot->bus,
101 slot->devfn,
102 hs_cap + 2,
103 hs_csr)) {
104 return 0;
105 }
106 return 1;
107}
108
109u16 cpci_get_hs_csr(struct slot* slot)
110{
111 int hs_cap;
112 u16 hs_csr;
113
114 hs_cap = pci_bus_find_capability(slot->bus,
115 slot->devfn,
116 PCI_CAP_ID_CHSWP);
117 if(!hs_cap) {
118 return 0xFFFF;
119 }
120
121 if(pci_bus_read_config_word(slot->bus,
122 slot->devfn,
123 hs_cap + 2,
124 &hs_csr)) {
125 return 0xFFFF;
126 }
127 return hs_csr;
128}
129
130#if 0
131u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr)
132{
133 int hs_cap;
134 u16 new_hs_csr;
135
136 hs_cap = pci_bus_find_capability(slot->bus,
137 slot->devfn,
138 PCI_CAP_ID_CHSWP);
139 if(!hs_cap) {
140 return 0xFFFF;
141 }
142
143 /* Write out the new value */
144 if(pci_bus_write_config_word(slot->bus,
145 slot->devfn,
146 hs_cap + 2,
147 hs_csr)) {
148 return 0xFFFF;
149 }
150
151 /* Read back what we just wrote out */
152 if(pci_bus_read_config_word(slot->bus,
153 slot->devfn,
154 hs_cap + 2,
155 &new_hs_csr)) {
156 return 0xFFFF;
157 }
158 return new_hs_csr;
159}
160#endif
161
162int cpci_check_and_clear_ins(struct slot* slot)
163{
164 int hs_cap;
165 u16 hs_csr;
166 int ins = 0;
167
168 hs_cap = pci_bus_find_capability(slot->bus,
169 slot->devfn,
170 PCI_CAP_ID_CHSWP);
171 if(!hs_cap) {
172 return 0;
173 }
174 if(pci_bus_read_config_word(slot->bus,
175 slot->devfn,
176 hs_cap + 2,
177 &hs_csr)) {
178 return 0;
179 }
180 if(hs_csr & HS_CSR_INS) {
181 /* Clear INS (by setting it) */
182 if(pci_bus_write_config_word(slot->bus,
183 slot->devfn,
184 hs_cap + 2,
185 hs_csr)) {
186 ins = 0;
187 }
188 ins = 1;
189 }
190 return ins;
191}
192
193int cpci_check_ext(struct slot* slot)
194{
195 int hs_cap;
196 u16 hs_csr;
197 int ext = 0;
198
199 hs_cap = pci_bus_find_capability(slot->bus,
200 slot->devfn,
201 PCI_CAP_ID_CHSWP);
202 if(!hs_cap) {
203 return 0;
204 }
205 if(pci_bus_read_config_word(slot->bus,
206 slot->devfn,
207 hs_cap + 2,
208 &hs_csr)) {
209 return 0;
210 }
211 if(hs_csr & HS_CSR_EXT) {
212 ext = 1;
213 }
214 return ext;
215}
216
217int cpci_clear_ext(struct slot* slot)
218{
219 int hs_cap;
220 u16 hs_csr;
221
222 hs_cap = pci_bus_find_capability(slot->bus,
223 slot->devfn,
224 PCI_CAP_ID_CHSWP);
225 if(!hs_cap) {
226 return -ENODEV;
227 }
228 if(pci_bus_read_config_word(slot->bus,
229 slot->devfn,
230 hs_cap + 2,
231 &hs_csr)) {
232 return -ENODEV;
233 }
234 if(hs_csr & HS_CSR_EXT) {
235 /* Clear EXT (by setting it) */
236 if(pci_bus_write_config_word(slot->bus,
237 slot->devfn,
238 hs_cap + 2,
239 hs_csr)) {
240 return -ENODEV;
241 }
242 }
243 return 0;
244}
245
246int cpci_led_on(struct slot* slot)
247{
248 int hs_cap;
249 u16 hs_csr;
250
251 hs_cap = pci_bus_find_capability(slot->bus,
252 slot->devfn,
253 PCI_CAP_ID_CHSWP);
254 if(!hs_cap) {
255 return -ENODEV;
256 }
257 if(pci_bus_read_config_word(slot->bus,
258 slot->devfn,
259 hs_cap + 2,
260 &hs_csr)) {
261 return -ENODEV;
262 }
263 if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
264 /* Set LOO */
265 hs_csr |= HS_CSR_LOO;
266 if(pci_bus_write_config_word(slot->bus,
267 slot->devfn,
268 hs_cap + 2,
269 hs_csr)) {
270 err("Could not set LOO for slot %s",
271 slot->hotplug_slot->name);
272 return -ENODEV;
273 }
274 }
275 return 0;
276}
277
278int cpci_led_off(struct slot* slot)
279{
280 int hs_cap;
281 u16 hs_csr;
282
283 hs_cap = pci_bus_find_capability(slot->bus,
284 slot->devfn,
285 PCI_CAP_ID_CHSWP);
286 if(!hs_cap) {
287 return -ENODEV;
288 }
289 if(pci_bus_read_config_word(slot->bus,
290 slot->devfn,
291 hs_cap + 2,
292 &hs_csr)) {
293 return -ENODEV;
294 }
295 if(hs_csr & HS_CSR_LOO) {
296 /* Clear LOO */
297 hs_csr &= ~HS_CSR_LOO;
298 if(pci_bus_write_config_word(slot->bus,
299 slot->devfn,
300 hs_cap + 2,
301 hs_csr)) {
302 err("Could not clear LOO for slot %s",
303 slot->hotplug_slot->name);
304 return -ENODEV;
305 }
306 }
307 return 0;
308}
309
310
311/*
312 * Device configuration functions
313 */
314
315static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev)
316{
317 u8 irq_pin;
318 int r;
319
320 dbg("%s - enter", __FUNCTION__);
321
322 /* NOTE: device already setup from prior scan */
323
324 /* FIXME: How would we know if we need to enable the expansion ROM? */
325 pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L);
326
327 /* Assign resources */
328 dbg("assigning resources for %02x:%02x.%x",
329 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
330 for (r = 0; r < 6; r++) {
331 struct resource *res = dev->resource + r;
332 if(res->flags)
333 pci_assign_resource(dev, r);
334 }
335 dbg("finished assigning resources for %02x:%02x.%x",
336 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
337
338 /* Does this function have an interrupt at all? */
339 dbg("checking for function interrupt");
340 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
341 if(irq_pin) {
342 dbg("function uses interrupt pin %d", irq_pin);
343 }
344
345 /*
346 * Need to explicitly set irq field to 0 so that it'll get assigned
347 * by the pcibios platform dependent code called by pci_enable_device.
348 */
349 dev->irq = 0;
350
351 dbg("enabling device");
352 pci_enable_device(dev); /* XXX check return */
353 dbg("now dev->irq = %d", dev->irq);
354 if(irq_pin && dev->irq) {
355 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
356 }
357
358 /* Can't use pci_insert_device at the moment, do it manually for now */
359 pci_proc_attach_device(dev);
360 dbg("notifying drivers");
361 //pci_announce_device_to_drivers(dev);
362 dbg("%s - exit", __FUNCTION__);
363 return 0;
364}
365
366static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev)
367{
368 int rc;
369 struct pci_bus* child;
370 struct resource* r;
371 u8 max, n;
372 u16 command;
373
374 dbg("%s - enter", __FUNCTION__);
375
376 /* Do basic bridge initialization */
377 rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
378 if(rc) {
379 printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__);
380 }
381 rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
382 if(rc) {
383 printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__);
384 }
385 rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
386 if(rc) {
387 printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__);
388 }
389
390 /*
391 * Set parent bridge's subordinate field so that configuration space
392 * access will work in pci_scan_bridge and friends.
393 */
394 max = pci_max_busnr();
395 bus->subordinate = max + 1;
396 pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1);
397
398 /* Scan behind bridge */
399 n = pci_scan_bridge(bus, dev, max, 2);
400 child = pci_find_bus(0, max + 1);
401 if (!child)
402 return -ENODEV;
403 pci_proc_attach_bus(child);
404
405 /*
406 * Update parent bridge's subordinate field if there were more bridges
407 * behind the bridge that was scanned.
408 */
409 if(n > max) {
410 bus->subordinate = n;
411 pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n);
412 }
413
414 /*
415 * Update the bridge resources of the bridge to accommodate devices
416 * behind it.
417 */
418 pci_bus_size_bridges(child);
419 pci_bus_assign_resources(child);
420
421 /* Enable resource mapping via command register */
422 command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
423 r = child->resource[0];
424 if(r && r->start) {
425 command |= PCI_COMMAND_IO;
426 }
427 r = child->resource[1];
428 if(r && r->start) {
429 command |= PCI_COMMAND_MEMORY;
430 }
431 r = child->resource[2];
432 if(r && r->start) {
433 command |= PCI_COMMAND_MEMORY;
434 }
435 rc = pci_write_config_word(dev, PCI_COMMAND, command);
436 if(rc) {
437 err("Error setting command register");
438 return rc;
439 }
440
441 /* Set bridge control register */
442 command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA;
443 rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command);
444 if(rc) {
445 err("Error setting bridge control register");
446 return rc;
447 }
448 dbg("%s - exit", __FUNCTION__);
449 return 0;
450}
451
452static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev,
453 struct pci_bus_wrapped *wrapped_bus)
454{
455 int rc;
456 struct pci_dev *dev = wrapped_dev->dev;
457 struct pci_bus *bus = wrapped_bus->bus;
458 struct slot* slot;
459
460 dbg("%s - enter", __FUNCTION__);
461
462 /*
463 * We need to fix up the hotplug representation with the Linux
464 * representation.
465 */
466 if(wrapped_dev->data) {
467 slot = (struct slot*) wrapped_dev->data;
468 slot->dev = dev;
469 }
470
471 /* If it's a bridge, scan behind it for devices */
472 if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
473 rc = cpci_configure_bridge(bus, dev);
474 if(rc)
475 return rc;
476 }
477
478 /* Actually configure device */
479 if(dev) {
480 rc = cpci_configure_dev(bus, dev);
481 if(rc)
482 return rc;
483 }
484 dbg("%s - exit", __FUNCTION__);
485 return 0;
486}
487
488static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev,
489 struct pci_bus_wrapped *wrapped_bus)
490{
491 struct pci_dev *dev = wrapped_dev->dev;
492 struct slot* slot;
493
494 dbg("%s - enter", __FUNCTION__);
495 if(!dev)
496 return -ENODEV;
497
498 /* Remove the Linux representation */
499 if(pci_remove_device_safe(dev)) {
500 err("Could not remove device\n");
501 return -1;
502 }
503
504 /*
505 * Now remove the hotplug representation.
506 */
507 if(wrapped_dev->data) {
508 slot = (struct slot*) wrapped_dev->data;
509 slot->dev = NULL;
510 } else {
511 dbg("No hotplug representation for %02x:%02x.%x",
512 dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
513 }
514 dbg("%s - exit", __FUNCTION__);
515 return 0;
516}
517
518static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus,
519 struct pci_dev_wrapped *wrapped_dev)
520{
521 struct pci_bus *bus = wrapped_bus->bus;
522 struct pci_bus *parent = bus->self->bus;
523
524 dbg("%s - enter", __FUNCTION__);
525
526 /* The cleanup code for proc entries regarding buses should be in the kernel... */
527 if(bus->procdir)
528 dbg("detach_pci_bus %s", bus->procdir->name);
529 pci_proc_detach_bus(bus);
530
531 /* The cleanup code should live in the kernel... */
532 bus->self->subordinate = NULL;
533
534 /* unlink from parent bus */
535 list_del(&bus->node);
536
537 /* Now, remove */
538 if(bus)
539 kfree(bus);
540
541 /* Update parent's subordinate field */
542 if(parent) {
543 u8 n = pci_bus_max_busnr(parent);
544 if(n < parent->subordinate) {
545 parent->subordinate = n;
546 pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n);
547 }
548 }
549 dbg("%s - exit", __FUNCTION__);
550 return 0;
551}
552
553static struct pci_visit configure_functions = {
554 .visit_pci_dev = configure_visit_pci_dev,
555};
556
557static struct pci_visit unconfigure_functions_phase2 = {
558 .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2,
559 .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2
560};
561
562
563int cpci_configure_slot(struct slot* slot)
564{
565 int rc = 0;
566
567 dbg("%s - enter", __FUNCTION__);
568
569 if(slot->dev == NULL) {
570 dbg("pci_dev null, finding %02x:%02x:%x",
571 slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
572 slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
573 }
574
575 /* Still NULL? Well then scan for it! */
576 if(slot->dev == NULL) {
577 int n;
578 dbg("pci_dev still null");
579
580 /*
581 * This will generate pci_dev structures for all functions, but
582 * we will only call this case when lookup fails.
583 */
584 n = pci_scan_slot(slot->bus, slot->devfn);
585 dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
586 if(n > 0)
587 pci_bus_add_devices(slot->bus);
588 slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
589 if(slot->dev == NULL) {
590 err("Could not find PCI device for slot %02x", slot->number);
591 return 0;
592 }
593 }
594 dbg("slot->dev = %p", slot->dev);
595 if(slot->dev) {
596 struct pci_dev *dev;
597 struct pci_dev_wrapped wrapped_dev;
598 struct pci_bus_wrapped wrapped_bus;
599 int i;
600
601 memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
602 memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
603
604 for (i = 0; i < 8; i++) {
605 dev = pci_find_slot(slot->bus->number,
606 PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i));
607 if(!dev)
608 continue;
609 wrapped_dev.dev = dev;
610 wrapped_bus.bus = slot->dev->bus;
611 if(i)
612 wrapped_dev.data = NULL;
613 else
614 wrapped_dev.data = (void*) slot;
615 rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
616 }
617 }
618
619 dbg("%s - exit, rc = %d", __FUNCTION__, rc);
620 return rc;
621}
622
623int cpci_unconfigure_slot(struct slot* slot)
624{
625 int rc = 0;
626 int i;
627 struct pci_dev_wrapped wrapped_dev;
628 struct pci_bus_wrapped wrapped_bus;
629 struct pci_dev *dev;
630
631 dbg("%s - enter", __FUNCTION__);
632
633 if(!slot->dev) {
634 err("No device for slot %02x\n", slot->number);
635 return -ENODEV;
636 }
637
638 memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
639 memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
640
641 for (i = 0; i < 8; i++) {
642 dev = pci_find_slot(slot->bus->number,
643 PCI_DEVFN(PCI_SLOT(slot->devfn), i));
644 if(dev) {
645 wrapped_dev.dev = dev;
646 wrapped_bus.bus = dev->bus;
647 if(i)
648 wrapped_dev.data = NULL;
649 else
650 wrapped_dev.data = (void*) slot;
651 dbg("%s - unconfigure phase 2", __FUNCTION__);
652 rc = pci_visit_dev(&unconfigure_functions_phase2,
653 &wrapped_dev,
654 &wrapped_bus);
655 if(rc)
656 break;
657 }
658 }
659 dbg("%s - exit, rc = %d", __FUNCTION__, rc);
660 return rc;
661}