Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 
 41 extern 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 
 56 u8 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 
 77 int 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 
109 u16 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
131 u16 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 
162 int 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 
193 int 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 
217 int 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 
246 int 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 
278 int 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 
315 static 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 
366 static 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 
452 static 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 
488 static 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 
518 static 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 
553 static struct pci_visit configure_functions = {
554         .visit_pci_dev = configure_visit_pci_dev,
555 };
556 
557 static 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 
563 int 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 
623 int 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 }
662 
  This page was automatically generated by the LXR engine.