Subversion Repositories HelenOS

Rev

Go to most recent revision | 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.     futex_down(&pci_conf_futex);
  89.     psycho_conf_read(dev, reg, &res, sizeof(uint8_t)); 
  90.     futex_up(&pci_conf_futex);
  91.     return res;
  92. }
  93.  
  94. uint16_t pci_conf_read_16(pci_dev_t *dev, int reg)
  95. {
  96.     uint16_t res;
  97.     futex_down(&pci_conf_futex);
  98.     psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint16_t));   
  99.     futex_up(&pci_conf_futex);
  100.     return res;
  101. }
  102.  
  103. uint32_t pci_conf_read_32(pci_dev_t *dev, int reg)
  104. {
  105.     uint32_t res;
  106.     futex_down(&pci_conf_futex);
  107.     psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint32_t));   
  108.     futex_up(&pci_conf_futex);
  109.     return res;
  110. }
  111.  
  112. static inline uint16_t invert_endianess_16(uint16_t x)
  113. {
  114.     return (x & 0xFF) << 8 | (x >> 8);
  115. }
  116.  
  117. static inline uint32_t invert_endianess_32(uint32_t x)
  118. {
  119.     return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | (x >> 24);
  120. }
  121.  
  122. static void psycho_conf_read(pci_dev_t *d, int reg, uint8_t *buf, int len)
  123. {  
  124.     switch (len) {
  125.         case 1:
  126.             buf[0] = pio_read_8(psycho_conf_addr(d, reg));
  127.             break;
  128.         case 2:
  129.             *((uint16_t *)buf) = invert_endianess_16(pio_read_16(psycho_conf_addr(d, reg)));
  130.             break;
  131.         case 4:
  132.             *((uint32_t *)buf) = invert_endianess_32(pio_read_32(psycho_conf_addr(d, reg)));
  133.             break;
  134.     }  
  135. }
  136.  
  137. static void psycho_conf_write(pci_dev_t *d, int reg, uint8_t *buf, int len)
  138. {  
  139.     switch (len) {
  140.         case 1:
  141.             pio_write_8(psycho_conf_addr(d, reg), buf[0]);
  142.             break;
  143.         case 2:
  144.             pio_write_16(psycho_conf_addr(d, reg), invert_endianess_16(*((uint16_t *)buf)));
  145.             break;
  146.         case 4:
  147.             pio_write_32(psycho_conf_addr(d, reg), invert_endianess_32(*((uint32_t *)buf)));
  148.             break;
  149.     }
  150. }
  151.  
  152. /* pci bus structure initialization */
  153. void pci_init_bus_data(pci_bus_t *bus, pci_bus_t *parent)
  154. {
  155.     if (parent != NULL) {
  156.         bus->data = parent->data;
  157.     }
  158. }
  159.  
  160. int pci_bus_init()
  161. {  
  162.     if(!psycho_init()) {
  163.         return 0;
  164.     }  
  165.     psycho_scan(); 
  166.     return 1;
  167. }
  168.  
  169. void pci_bus_clean()
  170. {
  171.     free(u2p_bases);
  172.     free(conf_bases);
  173. }