e9df10c42f78b7850d76d49430654f1329d15047
[coreboot.git] / payloads / libpayload / libpci / libpci.c
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 */
35 static 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 */
41 u8 pci_read_byte(struct pci_dev *dev, int pos)
42 {
43         return pci_read_config8(libpci_to_lb(dev), pos);
44 }
45
46 u16 pci_read_word(struct pci_dev *dev, int pos)
47 {
48         return pci_read_config16(libpci_to_lb(dev), pos);
49 }
50
51 u32 pci_read_long(struct pci_dev *dev, int pos)
52 {
53         return pci_read_config32(libpci_to_lb(dev), pos);
54 }
55
56 int 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
62 int 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
68 int 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
74 struct pci_access *pci_alloc(void)
75 {
76         struct pci_access *pacc = malloc(sizeof(*pacc));
77         return pacc;
78 }
79
80 void pci_init(struct pci_access *pacc)
81 {
82         memset(pacc, 0, sizeof(*pacc));
83 }
84
85 void pci_cleanup(__attribute__ ((unused)) struct pci_access *pacc)
86 {
87 }
88
89 void 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 static char invalid_pci_device_string[] = "invalid pci device string";
100
101 /* parse domain:bus:dev.func (with all components but "dev" optional)
102  * into filter.
103  * Returns NULL on success, a string pointer to the error message otherwise.
104  */
105 char *pci_filter_parse_slot(struct pci_filter* filter, const char* id)
106 {
107         char *endptr;
108
109         filter->func = filter->dev = filter->bus = filter->domain = -1;
110
111         char *funcp = strrchr(id, '.');
112         if (funcp) {
113                 filter->func = strtoul(funcp+1, &endptr, 0);
114                 if (endptr[0] != '\0') return invalid_pci_device_string;
115         }
116
117         char *devp = strrchr(id, ':');
118         if (!devp) {
119                 filter->dev = strtoul(id, &endptr, 0);
120         } else {
121                 filter->dev = strtoul(devp+1, &endptr, 0);
122         }
123         if (endptr != funcp) return invalid_pci_device_string;
124         if (!devp) return NULL;
125
126         char *busp = strchr(id, ':');
127         if (busp == devp) {
128                 filter->bus = strtoul(id, &endptr, 0);
129         } else {
130                 filter->bus = strtoul(busp+1, &endptr, 0);
131         }
132         if (endptr != funcp) return invalid_pci_device_string;
133         if (busp == devp) return NULL;
134
135         filter->domain = strtoul(id, &endptr, 0);
136         if (endptr != busp) return invalid_pci_device_string;
137
138         return NULL;
139 }
140
141 int pci_filter_match(struct pci_filter* pf, struct pci_dev* dev)
142 {
143         if ((pf->domain > -1) && (pf->domain != dev->domain))
144                 return 0;
145         if ((pf->bus > -1) && (pf->bus != dev->bus))
146                 return 0;
147         if ((pf->dev > -1) && (pf->dev != dev->dev))
148                 return 0;
149         if ((pf->func > -1) && (pf->func != dev->func))
150                 return 0;
151         if ((pf->vendor > -1) && (pf->vendor != dev->vendor_id))
152                 return 0;
153         if ((pf->device > -1) && (pf->device != dev->device_id))
154                 return 0;
155         return 1;
156 }
157
158 static struct pci_dev *pci_scan_single_bus(struct pci_dev *dev, int bus)
159 {
160         int devfn;
161         u32 val;
162         unsigned char hdr;
163
164         for (devfn = 0; devfn < 0x100; devfn++) {
165                 int func = devfn & 0x7;
166                 int slot = (devfn >> 3) & 0x1f;
167
168                 val = pci_read_config32(PCI_DEV(bus, slot, func),
169                                         REG_VENDOR_ID);
170
171                 if (val == 0xffffffff || val == 0x00000000 ||
172                     val == 0x0000ffff || val == 0xffff0000)
173                         continue;
174
175                 dev->next = malloc(sizeof(struct pci_dev));
176                 dev = dev->next;
177                 dev->domain = 0;
178                 dev->bus = bus;
179                 dev->dev = slot;
180                 dev->func = func;
181                 dev->vendor_id = val & 0xffff;
182                 dev->device_id = val >> 16;
183                 dev->next = 0;
184
185                 hdr = pci_read_config8(PCI_DEV(bus, slot, func),
186                                        REG_HEADER_TYPE);
187                 hdr &= 0x7F;
188
189                 if (hdr == HEADER_TYPE_BRIDGE || hdr == HEADER_TYPE_CARDBUS) {
190                         unsigned int busses;
191                         busses = pci_read_config32(PCI_DEV(bus, slot, func),
192                                                    REG_PRIMARY_BUS);
193                         busses = (busses >> 8) & 0xFF;
194
195                         /* Avoid recursion if the new bus is the same as
196                          * the old bus (insert lame The Who joke here) */
197
198                         if (busses != bus)
199                                 dev = pci_scan_single_bus(dev, busses);
200                 }
201         }
202
203         return dev;
204 }
205
206 void pci_scan_bus(struct pci_access* pacc)
207 {
208         struct pci_dev rootdev;
209         pci_scan_single_bus(&rootdev, 0);
210         pacc->devices = rootdev.next;
211 }
212
213 struct pci_dev *pci_get_dev(struct pci_access* pacc, u16 domain, u8 bus, u8 dev, u8 func)
214 {
215         struct pci_dev *cur = malloc(sizeof(*cur));
216         cur->domain = domain;
217         cur->bus = bus;
218         cur->dev = dev;
219         cur->func = func;
220         return cur;
221 }
222