xref: /aosp_15_r20/external/coreboot/payloads/libpayload/libpci/libpci.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2010 coresystems GmbH
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <libpayload.h>
30 #include <pci.h>
31 #include <pci/pci.h>
32 
33 /* libpci shim */
libpci_to_lb(struct pci_dev * dev)34 static pcidev_t libpci_to_lb(struct pci_dev *dev)
35 {
36 	return PCI_DEV(dev->bus, dev->dev, dev->func);
37 }
38 
39 /* libpci interface */
pci_read_byte(struct pci_dev * dev,int pos)40 u8 pci_read_byte(struct pci_dev *dev, int pos)
41 {
42 	return pci_read_config8(libpci_to_lb(dev), (uint16_t)pos);
43 }
44 
pci_read_word(struct pci_dev * dev,int pos)45 u16 pci_read_word(struct pci_dev *dev, int pos)
46 {
47 	return pci_read_config16(libpci_to_lb(dev), (uint16_t)pos);
48 }
49 
pci_read_long(struct pci_dev * dev,int pos)50 u32 pci_read_long(struct pci_dev *dev, int pos)
51 {
52 	return pci_read_config32(libpci_to_lb(dev), (uint16_t)pos);
53 }
54 
pci_write_byte(struct pci_dev * dev,int pos,u8 data)55 int pci_write_byte(struct pci_dev *dev, int pos, u8 data)
56 {
57 	pci_write_config8(libpci_to_lb(dev), (uint16_t)pos, data);
58 	return 1; /* success */
59 }
60 
pci_write_word(struct pci_dev * dev,int pos,u16 data)61 int pci_write_word(struct pci_dev *dev, int pos, u16 data)
62 {
63 	pci_write_config16(libpci_to_lb(dev), (uint16_t)pos, data);
64 	return 1; /* success */
65 }
66 
pci_write_long(struct pci_dev * dev,int pos,u32 data)67 int pci_write_long(struct pci_dev *dev, int pos, u32 data)
68 {
69 	pci_write_config32(libpci_to_lb(dev), (uint16_t)pos, data);
70 	return 1; /* success */
71 }
72 
pci_alloc(void)73 struct pci_access *pci_alloc(void)
74 {
75 	return malloc(sizeof(struct pci_access));
76 }
77 
pci_init(struct pci_access * pacc)78 void pci_init(struct pci_access *pacc)
79 {
80 	memset(pacc, 0, sizeof(*pacc));
81 }
82 
pci_cleanup(struct pci_access * pacc)83 void pci_cleanup(__attribute__((unused)) struct pci_access *pacc)
84 {
85 }
86 
pci_filter_init(struct pci_access * pacc,struct pci_filter * pf)87 void pci_filter_init(struct pci_access* pacc, struct pci_filter* pf)
88 {
89 	pf->domain = -1;
90 	pf->bus = -1;
91 	pf->dev = -1;
92 	pf->func = -1;
93 	pf->vendor = -1;
94 	pf->device = -1;
95 }
96 
97 static char invalid_pci_device_string[] = "invalid pci device string";
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  */
pci_filter_parse_slot(struct pci_filter * filter,const char * id)103 char *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 = strtol(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 = strtol(id, &endptr, 0);
118 	} else {
119 		filter->dev = strtol(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 = strtol(id, &endptr, 0);
127 	} else {
128 		filter->bus = strtol(busp+1, &endptr, 0);
129 	}
130 	if (endptr != funcp) return invalid_pci_device_string;
131 	if (busp == devp) return NULL;
132 
133 	filter->domain = strtol(id, &endptr, 0);
134 	if (endptr != busp) return invalid_pci_device_string;
135 
136 	return NULL;
137 }
138 
pci_filter_match(struct pci_filter * pf,struct pci_dev * dev)139 int 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 
pci_scan_single_bus(struct pci_dev * dev,uint8_t bus)156 static struct pci_dev *pci_scan_single_bus(struct pci_dev *dev, uint8_t bus)
157 {
158 	int devfn;
159 	u32 val;
160 	unsigned char hdr;
161 
162 	for (devfn = 0; devfn < 0x100; devfn++) {
163 		uint8_t func = devfn & 0x7;
164 		uint8_t 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 = (uint16_t)(val >> 16);
181 		dev->device_class = pci_read_config16(PCI_DEV(bus, slot, func), PCI_CLASS_DEVICE);
182 		dev->next = 0;
183 
184 		hdr = pci_read_config8(PCI_DEV(bus, slot, func),
185 				       REG_HEADER_TYPE);
186 		hdr &= 0x7F;
187 
188 		if (hdr == HEADER_TYPE_BRIDGE || hdr == HEADER_TYPE_CARDBUS) {
189 			uint8_t busses;
190 			busses = (uint8_t)(pci_read_config32(
191 				PCI_DEV(bus, slot, func),
192 				REG_PRIMARY_BUS) >> 8);
193 
194 			/* Avoid recursion if the new bus is the same as
195 			 * the old bus (insert lame The Who joke here) */
196 
197 			if (busses != bus)
198 				dev = pci_scan_single_bus(dev, busses);
199 		}
200 	}
201 
202 	return dev;
203 }
204 
pci_scan_bus(struct pci_access * pacc)205 void pci_scan_bus(struct pci_access* pacc)
206 {
207 	struct pci_dev rootdev;
208 	pci_scan_single_bus(&rootdev, 0);
209 	pacc->devices = rootdev.next;
210 }
211 
pci_get_dev(struct pci_access * pacc,u16 domain,u8 bus,u8 dev,u8 func)212 struct pci_dev *pci_get_dev(struct pci_access* pacc, u16 domain, u8 bus, u8 dev, u8 func)
213 {
214 	struct pci_dev *cur = malloc(sizeof(*cur));
215 	cur->domain = domain;
216 	cur->bus = bus;
217 	cur->dev = dev;
218 	cur->func = func;
219 	return cur;
220 }
221 
pci_free_dev(struct pci_dev * const dev)222 void pci_free_dev(struct pci_dev *const dev)
223 {
224 	free(dev);
225 }
226