Subversion Repositories HelenOS

Rev

Rev 4418 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <malloc.h>
  2. #include <assert.h>
  3. #include <unistd.h>
  4. #include <ddi.h>
  5. #include <libarch/ddi.h>
  6. #include <stdio.h>
  7. #include <futex.h>
  8.  
  9. #include "pci.h"
  10. #include "pci_bus.h"
  11.  
  12. #define PCI_CONF_OFFSET   0x001000000
  13. #define PCI_CONF_SIZE     0x001000000
  14.  
  15. /*
  16.  * virtual address of specified PCI configuration register:
  17.  * conf_base ... base address of configuration address space
  18.  * bus ... bus number
  19.  * dev ... device number (0 - 31)
  20.  * fn  ... function number (0 - 7)
  21.  * reg ... register number (register's position within PCI configuration header)
  22.  **/
  23. #define CONF_ADDR(conf_base, bus, dev, fn, reg)   ((void *)(conf_base + ((bus << 16) | (dev << 11) | (fn << 8) | reg)))
  24.  
  25. static atomic_t pci_conf_futex = FUTEX_INITIALIZER;
  26.  
  27. static long u2p_space_cnt = 0;
  28. static long *u2p_bases;
  29. /* virtual addresses of PCI configuration spaces */
  30. static void **conf_bases;  
  31.  
  32. static int psycho_init();
  33. static void u2p_bases_init();
  34. static void psycho_scan();
  35. static void * psycho_conf_addr(pci_dev_t *dev, int reg);
  36. static void psycho_conf_read(pci_dev_t *d, int reg, uint8_t *buf, int len);
  37. static void psycho_conf_write(pci_dev_t *d, int reg, uint8_t *buf, int len);
  38.  
  39.  
  40. static void * psycho_conf_addr(pci_dev_t *dev, int reg)
  41. {  
  42.     return CONF_ADDR(dev->bus->data, dev->bus->num, dev->dev, dev->fn, reg);
  43. }
  44.  
  45. static void psycho_scan()
  46. {  
  47.     printf("PCI: psycho_scan\n");
  48.     int i, num;
  49.     for (i = 0; i < u2p_space_cnt; i++) {
  50.         for (num = 0; num <= 0x80; num += 0x80) {      
  51.             pci_bus_t *bus = pci_alloc_bus();
  52.             bus->num = num;
  53.             bus->data = conf_bases[i];
  54.             pci_bus_register(bus);
  55.             pci_bus_scan(bus);
  56.         }
  57.     }
  58. }
  59.  
  60. static int psycho_init()
  61. {
  62.     printf("PCI: starting psycho initialization.\n");
  63.     u2p_bases_init();
  64.     conf_bases = (void **)malloc(u2p_space_cnt * sizeof(void *));  
  65.     int i, error;
  66.     for (i = 0; i < u2p_space_cnt; i++) {
  67.         if (error = pio_enable((void *)(u2p_bases[i] + PCI_CONF_OFFSET), PCI_CONF_SIZE, &(conf_bases[i]))) {
  68.             printf("PCI: failed to enable psycho conf. adr. space num. %d. (error %d)\n", i, error);
  69.             return 0;
  70.         }
  71.     }  
  72.     return 1;
  73. }
  74.  
  75. static void u2p_bases_init()
  76. {
  77.     // TODO: write this more generally - get this information from firmware (using kernel + sysinfo)   
  78.     u2p_space_cnt = 2;
  79.     //u2p_space_cnt = 1;
  80.     u2p_bases = (void **)malloc(u2p_space_cnt * sizeof(void *));
  81.     u2p_bases[0] = 0x1c800000000;
  82.     u2p_bases[1] = 0x1ca00000000;  
  83. }
  84.  
  85. uint8_t pci_conf_read_8(pci_dev_t *dev, int reg)
  86. {
  87.     uint8_t res;   
  88.     psycho_conf_read(dev, reg, &res, sizeof(uint8_t)); 
  89.     return res;
  90. }
  91.  
  92. uint16_t pci_conf_read_16(pci_dev_t *dev, int reg)
  93. {
  94.     uint16_t res;
  95.     psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint16_t));   
  96.     return res;
  97. }
  98.  
  99. uint32_t pci_conf_read_32(pci_dev_t *dev, int reg)
  100. {
  101.     uint32_t res;
  102.     psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint32_t));       
  103.     return res;
  104. }
  105.  
  106. static inline uint16_t invert_endianness_16(uint16_t x)
  107. {
  108.     return (x & 0xFF) << 8 | (x >> 8);
  109. }
  110.  
  111. static inline uint32_t invert_endianness_32(uint32_t x)
  112. {
  113.     return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | (x >> 24);
  114. }
  115.  
  116. static void psycho_conf_read(pci_dev_t *d, int reg, uint8_t *buf, int len)
  117. {  
  118.     futex_down(&pci_conf_futex);
  119.     switch (len) {
  120.         case 1:
  121.             buf[0] = pio_read_8(psycho_conf_addr(d, reg));
  122.             break;
  123.         case 2:
  124.             *((uint16_t *)buf) = invert_endianness_16(pio_read_16(psycho_conf_addr(d, reg)));
  125.             break;
  126.         case 4:
  127.             *((uint32_t *)buf) = invert_endianness_32(pio_read_32(psycho_conf_addr(d, reg)));
  128.             break;
  129.     }
  130.     futex_up(&pci_conf_futex);
  131. }
  132.  
  133. static void psycho_conf_write(pci_dev_t *d, int reg, uint8_t *buf, int len)
  134. {  
  135.     futex_down(&pci_conf_futex);
  136.     switch (len) {
  137.         case 1:
  138.             pio_write_8(psycho_conf_addr(d, reg), buf[0]);
  139.             break;
  140.         case 2:
  141.             pio_write_16(psycho_conf_addr(d, reg), invert_endianness_16(*((uint16_t *)buf)));
  142.             break;
  143.         case 4:
  144.             pio_write_32(psycho_conf_addr(d, reg), invert_endianness_32(*((uint32_t *)buf)));
  145.             break;
  146.     }
  147.     futex_up(&pci_conf_futex);
  148. }
  149.  
  150. /* pci bus structure initialization */
  151. void pci_init_bus_data(pci_bus_t *bus, pci_bus_t *parent)
  152. {
  153.     if (parent != NULL) {
  154.         bus->data = parent->data;
  155.     }
  156. }
  157.  
  158. int pci_bus_init()
  159. {  
  160.     if(!psycho_init()) {
  161.         return 0;
  162.     }  
  163.     psycho_scan(); 
  164.     return 1;
  165. }
  166.  
  167. void pci_bus_clean()
  168. {
  169.     free(u2p_bases);
  170.     free(conf_bases);
  171. }