coreboot/payloads/libpayload/libpci/libpci.c
<<
>>
Prefs
   1/*
   2 * This file is part of the libpayload project.
   3 *
   4 * Copyright (C) 2010 coresystems GmbH
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions
   8 * are met:
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions and the following disclaimer.
  11 * 2. Redistributions in binary form must reproduce the above copyright
  12 *    notice, this list of conditions and the following disclaimer in the
  13 *    documentation and/or other materials provided with the distribution.
  14 * 3. The name of the author may not be used to endorse or promote products
  15 *    derived from this software without specific prior written permission.
  16 *
  17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27 * SUCH DAMAGE.
  28 */
  29
  30#include <libpayload.h>
  31#include <pci.h>
  32#include <pci/pci.h>
  33
  34/* libpci shim */
  35static pcidev_t libpci_to_lb(struct pci_dev *dev)
  36{
  37        return PCI_DEV(dev->bus, dev->dev, dev->func);
  38}
  39
  40/* libpci interface */
  41u8 pci_read_byte(struct pci_dev *dev, int pos)
  42{
  43        return pci_read_config8(libpci_to_lb(dev), pos);
  44}
  45
  46u16 pci_read_word(struct pci_dev *dev, int pos)
  47{
  48        return pci_read_config16(libpci_to_lb(dev), pos);
  49}
  50
  51u32 pci_read_long(struct pci_dev *dev, int pos)
  52{
  53        return pci_read_config32(libpci_to_lb(dev), pos);
  54}
  55
  56int pci_write_byte(struct pci_dev *dev, int pos, u8 data)
  57{
  58        pci_write_config8(libpci_to_lb(dev), pos, data);
  59        return 1; /* success */
  60}
  61
  62int pci_write_word(struct pci_dev *dev, int pos, u16 data)
  63{
  64        pci_write_config16(libpci_to_lb(dev), pos, data);
  65        return 1; /* success */
  66}
  67
  68int pci_write_long(struct pci_dev *dev, int pos, u32 data)
  69{
  70        pci_write_config32(libpci_to_lb(dev), pos, data);
  71        return 1; /* success */
  72}
  73
  74struct pci_access *pci_alloc(void)
  75{
  76        struct pci_access *pacc = malloc(sizeof(*pacc));
  77        return pacc;
  78}
  79
  80void pci_init(struct pci_access *pacc)
  81{
  82        memset(pacc, 0, sizeof(*pacc));
  83}
  84
  85void pci_cleanup(__attribute__ ((unused)) struct pci_access *pacc)
  86{
  87}
  88
  89void pci_filter_init(struct pci_access* pacc, struct pci_filter* pf)
  90{
  91        pf->domain = -1;
  92        pf->bus = -1;
  93        pf->dev = -1;
  94        pf->func = -1;
  95        pf->vendor = -1;
  96        pf->device = -1;
  97}
  98
  99/* parse domain:bus:dev.func (with all components but "dev" optional)
 100 * into filter.
 101 * Returns NULL on success, a string pointer to the error message otherwise.
 102 */
 103char *pci_filter_parse_slot(struct pci_filter* filter, const char* id)
 104{
 105        char *endptr;
 106
 107        filter->func = filter->dev = filter->bus = filter->domain = -1;
 108
 109        char *funcp = strrchr(id, '.');
 110        if (funcp) {
 111                filter->func = strtoul(funcp+1, &endptr, 0);
 112                if (endptr[0] != '\0') return "invalid pci device string";
 113        }
 114
 115        char *devp = strrchr(id, ':');
 116        if (!devp) {
 117                filter->dev = strtoul(id, &endptr, 0);
 118        } else {
 119                filter->dev = strtoul(devp+1, &endptr, 0);
 120        }
 121        if (endptr != funcp) return "invalid pci device string";
 122        if (!devp) return NULL;
 123
 124        char *busp = strchr(id, ':');
 125        if (busp == devp) {
 126                filter->bus = strtoul(id, &endptr, 0);
 127        } else {
 128                filter->bus = strtoul(busp+1, &endptr, 0);
 129        }
 130        if (endptr != funcp) return "invalid pci device string";
 131        if (busp == devp) return NULL;
 132
 133        filter->domain = strtoul(id, &endptr, 0);
 134        if (endptr != busp) return "invalid pci device string";
 135
 136        return NULL;
 137}
 138
 139int pci_filter_match(struct pci_filter* pf, struct pci_dev* dev)
 140{
 141        if ((pf->domain > -1) && (pf->domain != dev->domain))
 142                return 0;
 143        if ((pf->bus > -1) && (pf->bus != dev->bus))
 144                return 0;
 145        if ((pf->dev > -1) && (pf->dev != dev->dev))
 146                return 0;
 147        if ((pf->func > -1) && (pf->func != dev->func))
 148                return 0;
 149        if ((pf->vendor > -1) && (pf->vendor != dev->vendor_id))
 150                return 0;
 151        if ((pf->device > -1) && (pf->device != dev->device_id))
 152                return 0;
 153        return 1;
 154}
 155
 156static struct pci_dev *pci_scan_single_bus(struct pci_dev *dev, int bus)
 157{
 158        int devfn;
 159        u32 val;
 160        unsigned char hdr;
 161
 162        for (devfn = 0; devfn < 0x100; devfn++) {
 163                int func = devfn & 0x7;
 164                int slot = (devfn >> 3) & 0x1f;
 165
 166                val = pci_read_config32(PCI_DEV(bus, slot, func),
 167                                        REG_VENDOR_ID);
 168
 169                if (val == 0xffffffff || val == 0x00000000 ||
 170                    val == 0x0000ffff || val == 0xffff0000)
 171                        continue;
 172
 173                dev->next = malloc(sizeof(struct pci_dev));
 174                dev = dev->next;
 175                dev->domain = 0;
 176                dev->bus = bus;
 177                dev->dev = slot;
 178                dev->func = func;
 179                dev->vendor_id = val & 0xffff;
 180                dev->device_id = val >> 16;
 181                dev->next = 0;
 182                
 183                hdr = pci_read_config8(PCI_DEV(bus, slot, func),
 184                                       REG_HEADER_TYPE);
 185                hdr &= 0x7F;
 186
 187                if (hdr == HEADER_TYPE_BRIDGE || hdr == HEADER_TYPE_CARDBUS) {
 188                        unsigned int busses;
 189                        busses = pci_read_config32(PCI_DEV(bus, slot, func),
 190                                                   REG_PRIMARY_BUS);
 191                        busses = (busses >> 8) & 0xFF;
 192
 193                        /* Avoid recursion if the new bus is the same as
 194                         * the old bus (insert lame The Who joke here) */
 195
 196                        if (busses != bus)
 197                                dev = pci_scan_single_bus(dev, busses);
 198                }
 199        }
 200
 201        return dev;
 202}
 203
 204void pci_scan_bus(struct pci_access* pacc)
 205{
 206        struct pci_dev rootdev;
 207        pci_scan_single_bus(&rootdev, 0);
 208        pacc->devices = rootdev.next;
 209}
 210
 211struct pci_dev *pci_get_dev(struct pci_access* pacc, u16 domain, u8 bus, u8 dev, u8 func)
 212{
 213        struct pci_dev *cur = malloc(sizeof(*cur));
 214        cur->domain = domain;
 215        cur->bus = bus;
 216        cur->dev = dev;
 217        cur->func = func;
 218        return cur;
 219}
 220
 221
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.