Subversion Repositories Kolibri OS

Rev

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

  1.  
  2. #include <ddk.h>
  3. #include <linux/errno.h>
  4. #include <mutex.h>
  5. #include <pci.h>
  6. #include <syscall.h>
  7.  
  8. LIST_HEAD(pci_root_buses);
  9.  
  10. #define IO_SPACE_LIMIT          0xffff
  11. #define PCIBIOS_SUCCESSFUL      0x00
  12.  
  13. struct resource ioport_resource = {
  14.     .name   = "PCI IO",
  15.     .start  = 0,
  16.     .end    = IO_SPACE_LIMIT,
  17.     .flags  = IORESOURCE_IO,
  18. };
  19.  
  20. struct resource iomem_resource = {
  21.     .name   = "PCI mem",
  22.     .start  = 0,
  23.     .end    = -1,
  24.     .flags  = IORESOURCE_MEM,
  25. };
  26.  
  27. #define PCI_FIND_CAP_TTL    48
  28.  
  29. static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
  30.                    u8 pos, int cap, int *ttl)
  31. {
  32.     u8 id;
  33.  
  34.     while ((*ttl)--) {
  35.         pci_bus_read_config_byte(bus, devfn, pos, &pos);
  36.         if (pos < 0x40)
  37.             break;
  38.         pos &= ~3;
  39.         pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID,
  40.                      &id);
  41.         if (id == 0xff)
  42.             break;
  43.         if (id == cap)
  44.             return pos;
  45.         pos += PCI_CAP_LIST_NEXT;
  46.     }
  47.     return 0;
  48. }
  49.  
  50. static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
  51.                    u8 pos, int cap)
  52. {
  53.     int ttl = PCI_FIND_CAP_TTL;
  54.  
  55.     return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
  56. }
  57. static int __pci_bus_find_cap_start(struct pci_bus *bus,
  58.                     unsigned int devfn, u8 hdr_type)
  59. {
  60.     u16 status;
  61.  
  62.     pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
  63.     if (!(status & PCI_STATUS_CAP_LIST))
  64.         return 0;
  65.  
  66.     switch (hdr_type) {
  67.     case PCI_HEADER_TYPE_NORMAL:
  68.     case PCI_HEADER_TYPE_BRIDGE:
  69.         return PCI_CAPABILITY_LIST;
  70.     case PCI_HEADER_TYPE_CARDBUS:
  71.         return PCI_CB_CAPABILITY_LIST;
  72.     default:
  73.         return 0;
  74.     }
  75.  
  76.     return 0;
  77. }
  78.  
  79.  
  80. /**
  81.  * pci_find_capability - query for devices' capabilities
  82.  * @dev: PCI device to query
  83.  * @cap: capability code
  84.  *
  85.  * Tell if a device supports a given PCI capability.
  86.  * Returns the address of the requested capability structure within the
  87.  * device's PCI configuration space or 0 in case the device does not
  88.  * support it.  Possible values for @cap:
  89.  *
  90.  *  %PCI_CAP_ID_PM           Power Management
  91.  *  %PCI_CAP_ID_AGP          Accelerated Graphics Port
  92.  *  %PCI_CAP_ID_VPD          Vital Product Data
  93.  *  %PCI_CAP_ID_SLOTID       Slot Identification
  94.  *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
  95.  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap
  96.  *  %PCI_CAP_ID_PCIX         PCI-X
  97.  *  %PCI_CAP_ID_EXP          PCI Express
  98.  */
  99. int pci_find_capability(struct pci_dev *dev, int cap)
  100. {
  101.     int pos;
  102.  
  103.     pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
  104.     if (pos)
  105.         pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);
  106.  
  107.     return pos;
  108. }
  109.  
  110.  
  111. static struct pci_bus * pci_alloc_bus(void)
  112. {
  113.     struct pci_bus *b;
  114.  
  115.     b = kzalloc(sizeof(*b), GFP_KERNEL);
  116.     if (b) {
  117.         INIT_LIST_HEAD(&b->node);
  118.         INIT_LIST_HEAD(&b->children);
  119.         INIT_LIST_HEAD(&b->devices);
  120.         INIT_LIST_HEAD(&b->slots);
  121.         INIT_LIST_HEAD(&b->resources);
  122.     }
  123.     return b;
  124. }
  125.  
  126. struct pci_bus * pci_create_bus(int bus, struct pci_ops *ops, void *sysdata)
  127. {
  128.     int error;
  129.     struct pci_bus *b, *b2;
  130.  
  131.     b = pci_alloc_bus();
  132.     if (!b)
  133.         return NULL;
  134.  
  135.     b->sysdata = sysdata;
  136.     b->ops = ops;
  137.  
  138.     b2 = pci_find_bus(pci_domain_nr(b), bus);
  139.     if (b2) {
  140.         /* If we already got to this bus through a different bridge, ignore it */
  141.         dbgprintf("bus already known\n");
  142.         goto err_out;
  143.     }
  144.  
  145. //    down_write(&pci_bus_sem);
  146.     list_add_tail(&b->node, &pci_root_buses);
  147. //    up_write(&pci_bus_sem);
  148.  
  149.     b->number = b->secondary = bus;
  150.     b->resource[0] = &ioport_resource;
  151.     b->resource[1] = &iomem_resource;
  152.  
  153.     return b;
  154.  
  155. err_out:
  156.     kfree(b);
  157.     return NULL;
  158. }
  159.  
  160.  
  161.  
  162.  
  163.  
  164. static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
  165. {
  166.     struct pci_bus* child;
  167.     struct list_head *tmp;
  168.  
  169.     if(bus->number == busnr)
  170.         return bus;
  171.  
  172.     list_for_each(tmp, &bus->children) {
  173.         child = pci_do_find_bus(pci_bus_b(tmp), busnr);
  174.         if(child)
  175.             return child;
  176.     }
  177.     return NULL;
  178. }
  179.  
  180.  
  181. /**
  182.  * pci_find_bus - locate PCI bus from a given domain and bus number
  183.  * @domain: number of PCI domain to search
  184.  * @busnr: number of desired PCI bus
  185.  *
  186.  * Given a PCI bus number and domain number, the desired PCI bus is located
  187.  * in the global list of PCI buses.  If the bus is found, a pointer to its
  188.  * data structure is returned.  If no bus is found, %NULL is returned.
  189.  */
  190. struct pci_bus * pci_find_bus(int domain, int busnr)
  191. {
  192.     struct pci_bus *bus = NULL;
  193.     struct pci_bus *tmp_bus;
  194.  
  195.     while ((bus = pci_find_next_bus(bus)) != NULL)  {
  196.         if (pci_domain_nr(bus) != domain)
  197.             continue;
  198.         tmp_bus = pci_do_find_bus(bus, busnr);
  199.         if (tmp_bus)
  200.             return tmp_bus;
  201.     }
  202.     return NULL;
  203. }
  204.  
  205. /**
  206.  * pci_find_next_bus - begin or continue searching for a PCI bus
  207.  * @from: Previous PCI bus found, or %NULL for new search.
  208.  *
  209.  * Iterates through the list of known PCI busses.  A new search is
  210.  * initiated by passing %NULL as the @from argument.  Otherwise if
  211.  * @from is not %NULL, searches continue from next device on the
  212.  * global list.
  213.  */
  214. struct pci_bus *
  215. pci_find_next_bus(const struct pci_bus *from)
  216. {
  217.     struct list_head *n;
  218.     struct pci_bus *b = NULL;
  219.  
  220. //    WARN_ON(in_interrupt());
  221. //    down_read(&pci_bus_sem);
  222.     n = from ? from->node.next : pci_root_buses.next;
  223.     if (n != &pci_root_buses)
  224.         b = pci_bus_b(n);
  225. //    up_read(&pci_bus_sem);
  226.     return b;
  227. }
  228.  
  229.  
  230. /**
  231.  * pci_get_slot - locate PCI device for a given PCI slot
  232.  * @bus: PCI bus on which desired PCI device resides
  233.  * @devfn: encodes number of PCI slot in which the desired PCI
  234.  * device resides and the logical device number within that slot
  235.  * in case of multi-function devices.
  236.  *
  237.  * Given a PCI bus and slot/function number, the desired PCI device
  238.  * is located in the list of PCI devices.
  239.  * If the device is found, its reference count is increased and this
  240.  * function returns a pointer to its data structure.  The caller must
  241.  * decrement the reference count by calling pci_dev_put().
  242.  * If no device is found, %NULL is returned.
  243.  */
  244. struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
  245. {
  246.     struct list_head *tmp;
  247.     struct pci_dev *dev;
  248.  
  249. //    WARN_ON(in_interrupt());
  250. //    down_read(&pci_bus_sem);
  251.  
  252.     list_for_each(tmp, &bus->devices) {
  253.         dev = pci_dev_b(tmp);
  254.         if (dev->devfn == devfn)
  255.             goto out;
  256.     }
  257.  
  258.     dev = NULL;
  259.  out:
  260. //    pci_dev_get(dev);
  261. //    up_read(&pci_bus_sem);
  262.     return dev;
  263. }
  264.  
  265.  
  266.  
  267.  
  268. /**
  269.  * pci_find_ext_capability - Find an extended capability
  270.  * @dev: PCI device to query
  271.  * @cap: capability code
  272.  *
  273.  * Returns the address of the requested extended capability structure
  274.  * within the device's PCI configuration space or 0 if the device does
  275.  * not support it.  Possible values for @cap:
  276.  *
  277.  *  %PCI_EXT_CAP_ID_ERR     Advanced Error Reporting
  278.  *  %PCI_EXT_CAP_ID_VC      Virtual Channel
  279.  *  %PCI_EXT_CAP_ID_DSN     Device Serial Number
  280.  *  %PCI_EXT_CAP_ID_PWR     Power Budgeting
  281.  */
  282. int pci_find_ext_capability(struct pci_dev *dev, int cap)
  283. {
  284.     u32 header;
  285.     int ttl;
  286.     int pos = PCI_CFG_SPACE_SIZE;
  287.  
  288.     /* minimum 8 bytes per capability */
  289.     ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
  290.  
  291.     if (dev->cfg_size <= PCI_CFG_SPACE_SIZE)
  292.         return 0;
  293.  
  294.     if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
  295.         return 0;
  296.  
  297.     /*
  298.      * If we have no capabilities, this is indicated by cap ID,
  299.      * cap version and next pointer all being 0.
  300.      */
  301.     if (header == 0)
  302.         return 0;
  303.  
  304.     while (ttl-- > 0) {
  305.         if (PCI_EXT_CAP_ID(header) == cap)
  306.             return pos;
  307.  
  308.         pos = PCI_EXT_CAP_NEXT(header);
  309.         if (pos < PCI_CFG_SPACE_SIZE)
  310.             break;
  311.  
  312.         if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
  313.             break;
  314.     }
  315.  
  316.     return 0;
  317. }
  318.  
  319.