Subversion Repositories HelenOS

Rev

Rev 1307 | Rev 1787 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  The PCI Library -- Direct Configuration access via i386 Ports
  3.  *
  4.  *  Copyright (c) 1997--2004 Martin Mares <mj@ucw.cz>
  5.  *
  6.  *  May 8, 2006 - Modified and ported to HelenOS by Jakub Jermar.
  7.  *
  8.  *  Can be freely distributed and used under the terms of the GNU GPL.
  9.  */
  10.  
  11. #include <unistd.h>
  12.  
  13. #include "internal.h"
  14.  
  15. static inline void outb(u8 b, u16 port)
  16. {
  17.     asm volatile ("outb %0, %1\n" :: "a" (b), "d" (port));
  18. }
  19.  
  20. static inline void outw(u16 w, u16 port)
  21. {
  22.     asm volatile ("outw %0, %1\n" :: "a" (w), "d" (port));
  23. }
  24.  
  25. static inline void outl(u32 l, u16 port)
  26. {
  27.     asm volatile ("outl %0, %1\n" :: "a" (l), "d" (port));
  28. }
  29.  
  30. static inline u8 inb(u16 port)
  31. {
  32.     u8 val;
  33.  
  34.     asm volatile ("inb %1, %0 \n" : "=a" (val) : "d"(port));
  35.     return val;
  36. }
  37.  
  38. static inline u16 inw(u16 port)
  39. {
  40.     u16 val;
  41.  
  42.     asm volatile ("inw %1, %0 \n" : "=a" (val) : "d"(port));
  43.     return val;
  44. }
  45.  
  46. static inline u32 inl(u16 port)
  47. {
  48.     u32 val;
  49.  
  50.     asm volatile ("inl %1, %0 \n" : "=a" (val) : "d"(port));
  51.     return val;
  52. }
  53.  
  54. static void conf12_init(struct pci_access *a)
  55. {
  56. }
  57.  
  58. static void conf12_cleanup(struct pci_access *a UNUSED)
  59. {
  60. }
  61.  
  62. /*
  63.  * Before we decide to use direct hardware access mechanisms, we try to do some
  64.  * trivial checks to ensure it at least _seems_ to be working -- we just test
  65.  * whether bus 00 contains a host bridge (this is similar to checking
  66.  * techniques used in XFree86, but ours should be more reliable since we
  67.  * attempt to make use of direct access hints provided by the PCI BIOS).
  68.  *
  69.  * This should be close to trivial, but it isn't, because there are buggy
  70.  * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
  71.  */
  72.  
  73. static int intel_sanity_check(struct pci_access *a, struct pci_methods *m)
  74. {
  75.     struct pci_dev d;
  76.  
  77.     a->debug("...sanity check");
  78.     d.bus = 0;
  79.     d.func = 0;
  80.     for (d.dev = 0; d.dev < 32; d.dev++) {
  81.         u16 class, vendor;
  82.         if (m->read(&d, PCI_CLASS_DEVICE, (byte *) & class,
  83.              sizeof(class))
  84.             && (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST)
  85.             || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA))
  86.             || m->read(&d, PCI_VENDOR_ID, (byte *) & vendor,
  87.                    sizeof(vendor))
  88.             && (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL)
  89.             || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ))) {
  90.             a->debug("...outside the Asylum at 0/%02x/0",
  91.                  d.dev);
  92.             return 1;
  93.         }
  94.     }
  95.     a->debug("...insane");
  96.     return 0;
  97. }
  98.  
  99. /*
  100.  *  Configuration type 1
  101.  */
  102.  
  103. #define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
  104.  
  105. static int conf1_detect(struct pci_access *a)
  106. {
  107.     unsigned int tmp;
  108.     int res = 0;
  109.  
  110.     outb(0x01, 0xCFB);
  111.     tmp = inl(0xCF8);
  112.     outl(0x80000000, 0xCF8);
  113.     if (inl(0xCF8) == 0x80000000)
  114.         res = 1;
  115.     outl(tmp, 0xCF8);
  116.     if (res)
  117.         res = intel_sanity_check(a, &pm_intel_conf1);
  118.     return res;
  119. }
  120.  
  121. static int conf1_read(struct pci_dev *d, int pos, byte * buf, int len)
  122. {
  123.     int addr = 0xcfc + (pos & 3);
  124.  
  125.     if (pos >= 256)
  126.         return 0;
  127.  
  128.     outl(0x80000000 | ((d->bus & 0xff) << 16) |
  129.          (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3), 0xcf8);
  130.  
  131.     switch (len) {
  132.     case 1:
  133.         buf[0] = inb(addr);
  134.         break;
  135.     case 2:
  136.         ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
  137.         break;
  138.     case 4:
  139.         ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
  140.         break;
  141.     default:
  142.         return pci_generic_block_read(d, pos, buf, len);
  143.     }
  144.     return 1;
  145. }
  146.  
  147. static int conf1_write(struct pci_dev *d, int pos, byte * buf, int len)
  148. {
  149.     int addr = 0xcfc + (pos & 3);
  150.  
  151.     if (pos >= 256)
  152.         return 0;
  153.  
  154.     outl(0x80000000 | ((d->bus & 0xff) << 16) |
  155.          (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3), 0xcf8);
  156.  
  157.     switch (len) {
  158.     case 1:
  159.         outb(buf[0], addr);
  160.         break;
  161.     case 2:
  162.         outw(le16_to_cpu(((u16 *) buf)[0]), addr);
  163.         break;
  164.     case 4:
  165.         outl(le32_to_cpu(((u32 *) buf)[0]), addr);
  166.         break;
  167.     default:
  168.         return pci_generic_block_write(d, pos, buf, len);
  169.     }
  170.     return 1;
  171. }
  172.  
  173. /*
  174.  *  Configuration type 2. Obsolete and brain-damaged, but existing.
  175.  */
  176.  
  177. static int conf2_detect(struct pci_access *a)
  178. {
  179.     /* This is ugly and tends to produce false positives. Beware. */
  180.     outb(0x00, 0xCFB);
  181.     outb(0x00, 0xCF8);
  182.     outb(0x00, 0xCFA);
  183.     if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
  184.         return intel_sanity_check(a, &pm_intel_conf2);
  185.     else
  186.         return 0;
  187. }
  188.  
  189. static int conf2_read(struct pci_dev *d, int pos, byte * buf, int len)
  190. {
  191.     int addr = 0xc000 | (d->dev << 8) | pos;
  192.  
  193.     if (pos >= 256)
  194.         return 0;
  195.  
  196.     if (d->dev >= 16)
  197.         /* conf2 supports only 16 devices per bus */
  198.         return 0;
  199.     outb((d->func << 1) | 0xf0, 0xcf8);
  200.     outb(d->bus, 0xcfa);
  201.     switch (len) {
  202.     case 1:
  203.         buf[0] = inb(addr);
  204.         break;
  205.     case 2:
  206.         ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
  207.         break;
  208.     case 4:
  209.         ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
  210.         break;
  211.     default:
  212.         outb(0, 0xcf8);
  213.         return pci_generic_block_read(d, pos, buf, len);
  214.     }
  215.     outb(0, 0xcf8);
  216.     return 1;
  217. }
  218.  
  219. static int conf2_write(struct pci_dev *d, int pos, byte * buf, int len)
  220. {
  221.     int addr = 0xc000 | (d->dev << 8) | pos;
  222.  
  223.     if (pos >= 256)
  224.         return 0;
  225.  
  226.     if (d->dev >= 16)
  227.         d->access->error("conf2_write: only first 16 devices exist.");
  228.     outb((d->func << 1) | 0xf0, 0xcf8);
  229.     outb(d->bus, 0xcfa);
  230.     switch (len) {
  231.     case 1:
  232.         outb(buf[0], addr);
  233.         break;
  234.     case 2:
  235.         outw(le16_to_cpu(*(u16 *) buf), addr);
  236.         break;
  237.     case 4:
  238.         outl(le32_to_cpu(*(u32 *) buf), addr);
  239.         break;
  240.     default:
  241.         outb(0, 0xcf8);
  242.         return pci_generic_block_write(d, pos, buf, len);
  243.     }
  244.     outb(0, 0xcf8);
  245.     return 1;
  246. }
  247.  
  248. struct pci_methods pm_intel_conf1 = {
  249.     "Intel-conf1",
  250.     NULL,           /* config */
  251.     conf1_detect,
  252.     conf12_init,
  253.     conf12_cleanup,
  254.     pci_generic_scan,
  255.     pci_generic_fill_info,
  256.     conf1_read,
  257.     conf1_write,
  258.     NULL,           /* init_dev */
  259.     NULL            /* cleanup_dev */
  260. };
  261.  
  262. struct pci_methods pm_intel_conf2 = {
  263.     "Intel-conf2",
  264.     NULL,           /* config */
  265.     conf2_detect,
  266.     conf12_init,
  267.     conf12_cleanup,
  268.     pci_generic_scan,
  269.     pci_generic_fill_info,
  270.     conf2_read,
  271.     conf2_write,
  272.     NULL,           /* init_dev */
  273.     NULL            /* cleanup_dev */
  274. };
  275.