Subversion Repositories HelenOS

Rev

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