iPXE
pcicloud.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26#include <stdint.h>
27#include <string.h>
28#include <ipxe/pci.h>
29#include <ipxe/pcicloud.h>
30
31/** @file
32 *
33 * Cloud VM PCI configuration space access
34 *
35 */
36
37/** Cached PCI configuration space access API */
38static struct {
39 /** PCI bus:dev.fn address range */
41 /** API for this bus:dev.fn address */
42 struct pci_api *api;
44
45/**
46 * Find PCI configuration space access API for address
47 *
48 * @v busdevfn Starting PCI bus:dev.fn address
49 * @v range PCI bus:dev.fn address range to fill in
50 * @ret api Configuration space access API, or NULL
51 */
53 struct pci_range *range ) {
54 struct pci_range candidate;
55 struct pci_api *api;
56 uint32_t best = 0;
59 uint32_t last;
60
61 /* Return empty range on error */
62 range->count = 0;
63
64 /* Try discovery via all known APIs */
66
67 /* Discover via this API */
68 api->pci_discover ( busdevfn, &candidate );
69
70 /* Check for a matching or new closest allocation */
71 index = ( busdevfn - candidate.start );
72 if ( ( index < candidate.count ) || ( index > best ) ) {
73 memcpy ( range, &candidate, sizeof ( *range ) );
74 best = index;
75 }
76
77 /* Stop if this range contains the target bus:dev.fn address */
78 if ( index < candidate.count ) {
79 first = range->start;
80 last = ( range->start + range->count - 1 );
81 DBGC ( &pcicloud, "PCICLOUD [" PCI_FMT "," PCI_FMT ") "
82 "using %s API\n", PCI_SEG ( first ),
83 PCI_BUS ( first ), PCI_SLOT ( first ),
84 PCI_FUNC ( first ), PCI_SEG ( last ),
85 PCI_BUS ( last ), PCI_SLOT ( last ),
86 PCI_FUNC ( last ), api->name );
87 return api;
88 }
89 }
90
91 return NULL;
92}
93
94/**
95 * Find next PCI bus:dev.fn address range in system
96 *
97 * @v busdevfn Starting PCI bus:dev.fn address
98 * @v range PCI bus:dev.fn address range to fill in
99 */
101
102 /* Find new range, if any */
104}
105
106/**
107 * Find configuration space access API for PCI device
108 *
109 * @v pci PCI device
110 * @ret api Configuration space access API
111 */
112static struct pci_api * pcicloud_api ( struct pci_device *pci ) {
113 struct pci_range *range = &pcicloud.range;
114 struct pci_api *api;
116 uint32_t last;
117
118 /* Reuse cached API if applicable */
119 if ( ( pci->busdevfn - range->start ) < range->count )
120 return pcicloud.api;
121
122 /* Find highest priority API claiming this range */
123 api = pcicloud_find ( pci->busdevfn, range );
124
125 /* Fall back to lowest priority API for any unclaimed gaps in ranges */
126 if ( ! api ) {
127 api = ( table_end ( PCI_APIS ) - 1 );
128 range->count = ( range->start - pci->busdevfn );
129 range->start = pci->busdevfn;
130 first = range->start;
131 last = ( range->start + range->count - 1 );
132 DBGC ( &pcicloud, "PCICLOUD [" PCI_FMT "," PCI_FMT ") falling "
133 "back to %s API\n", PCI_SEG ( first ),
134 PCI_BUS ( first ), PCI_SLOT ( first ),
135 PCI_FUNC ( first ), PCI_SEG ( last ), PCI_BUS ( last ),
136 PCI_SLOT ( last ), PCI_FUNC ( last ), api->name );
137 }
138
139 /* Cache API for this range */
140 pcicloud.api = api;
141
142 return api;
143}
144
145/**
146 * Check if PCI bus probing is allowed
147 *
148 * @v pci PCI device
149 * @ret ok Bus probing is allowed
150 */
151static int pcicloud_can_probe ( struct pci_device *pci ) {
152 struct pci_api *api = pcicloud_api ( pci );
153
154 return api->pci_can_probe ( pci );
155}
156
157/**
158 * Read byte from PCI configuration space
159 *
160 * @v pci PCI device
161 * @v where Location within PCI configuration space
162 * @v value Value read
163 * @ret rc Return status code
164 */
165static int pcicloud_read_config_byte ( struct pci_device *pci,
166 unsigned int where, uint8_t *value ) {
167 struct pci_api *api = pcicloud_api ( pci );
168
169 return api->pci_read_config_byte ( pci, where, value );
170}
171
172/**
173 * Read 16-bit word from PCI configuration space
174 *
175 * @v pci PCI device
176 * @v where Location within PCI configuration space
177 * @v value Value read
178 * @ret rc Return status code
179 */
180static int pcicloud_read_config_word ( struct pci_device *pci,
181 unsigned int where, uint16_t *value ) {
182 struct pci_api *api = pcicloud_api ( pci );
183
184 return api->pci_read_config_word ( pci, where, value );
185}
186
187/**
188 * Read 32-bit dword from PCI configuration space
189 *
190 * @v pci PCI device
191 * @v where Location within PCI configuration space
192 * @v value Value read
193 * @ret rc Return status code
194 */
195static int pcicloud_read_config_dword ( struct pci_device *pci,
196 unsigned int where, uint32_t *value ) {
197 struct pci_api *api = pcicloud_api ( pci );
198
199 return api->pci_read_config_dword ( pci, where, value );
200}
201
202/**
203 * Write byte to PCI configuration space
204 *
205 * @v pci PCI device
206 * @v where Location within PCI configuration space
207 * @v value Value to be written
208 * @ret rc Return status code
209 */
210static int pcicloud_write_config_byte ( struct pci_device *pci,
211 unsigned int where, uint8_t value ) {
212 struct pci_api *api = pcicloud_api ( pci );
213
214 return api->pci_write_config_byte ( pci, where, value );
215}
216
217/**
218 * Write 16-bit word to PCI configuration space
219 *
220 * @v pci PCI device
221 * @v where Location within PCI configuration space
222 * @v value Value to be written
223 * @ret rc Return status code
224 */
225static int pcicloud_write_config_word ( struct pci_device *pci,
226 unsigned int where, uint16_t value ) {
227 struct pci_api *api = pcicloud_api ( pci );
228
229 return api->pci_write_config_word ( pci, where, value );
230}
231
232/**
233 * Write 32-bit dword to PCI configuration space
234 *
235 * @v pci PCI device
236 * @v where Location within PCI configuration space
237 * @v value Value to be written
238 * @ret rc Return status code
239 */
241 unsigned int where, uint32_t value ) {
242 struct pci_api *api = pcicloud_api ( pci );
243
244 return api->pci_write_config_dword ( pci, where, value );
245}
246
247/**
248 * Map PCI bus address as an I/O address
249 *
250 * @v bus_addr PCI bus address
251 * @v len Length of region
252 * @ret io_addr I/O address, or NULL on error
253 */
254static void * pcicloud_ioremap ( struct pci_device *pci,
255 unsigned long bus_addr, size_t len ) {
256 struct pci_api *api = pcicloud_api ( pci );
257
258 return api->pci_ioremap ( pci, bus_addr, len );
259}
260
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
pseudo_bit_t value[0x00020]
Definition arbel.h:2
unsigned short uint16_t
Definition stdint.h:11
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
long index
Definition bigint.h:65
ring len
Length.
Definition dwmac.h:226
uint16_t busdevfn
PCI bus:dev.fn address.
Definition ena.h:17
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
int pci_read_config_dword(struct pci_device *pci, unsigned int where, uint32_t *value)
Read 32-bit dword from PCI configuration space.
int pci_can_probe(struct pci_device *pci)
Check if PCI bus probing is allowed.
void pci_discover(uint32_t busdevfn, struct pci_range *range)
Find next PCI bus:dev.fn address range in system.
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
void * pci_ioremap(struct pci_device *pci, unsigned long bus_addr, size_t len)
Map PCI bus address as an I/O address.
int pci_write_config_byte(struct pci_device *pci, unsigned int where, uint8_t value)
Write byte to PCI configuration space.
int pci_write_config_word(struct pci_device *pci, unsigned int where, uint16_t value)
Write 16-bit word to PCI configuration space.
int pci_read_config_byte(struct pci_device *pci, unsigned int where, uint8_t *value)
Read byte from PCI configuration space.
#define PROVIDE_PCIAPI(_subsys, _api_func, _func)
Provide a PCI I/O API implementation.
Definition pci_io.h:51
int pci_write_config_dword(struct pci_device *pci, unsigned int where, uint32_t value)
Write 32-bit dword to PCI configuration space.
#define PCI_APIS
Runtime selectable PCI API table.
Definition pci_io.h:180
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
uint32_t first
First block in range.
Definition pccrr.h:1
PCI bus.
#define PCI_FMT
PCI device debug message format.
Definition pci.h:312
#define PCI_SEG(busdevfn)
Definition pci.h:283
#define PCI_FUNC(busdevfn)
Definition pci.h:286
#define PCI_BUS(busdevfn)
Definition pci.h:284
#define PCI_SLOT(busdevfn)
Definition pci.h:285
static __always_inline void unsigned long bus_addr
Definition pcibios.h:156
static __always_inline int unsigned int where
Definition pcibios.h:57
static int pcicloud_write_config_dword(struct pci_device *pci, unsigned int where, uint32_t value)
Write 32-bit dword to PCI configuration space.
Definition pcicloud.c:240
static int pcicloud_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
Definition pcicloud.c:180
struct pci_api * api
API for this bus:dev.fn address.
Definition pcicloud.c:42
static struct pci_api * pcicloud_find(uint32_t busdevfn, struct pci_range *range)
Find PCI configuration space access API for address.
Definition pcicloud.c:52
static void * pcicloud_ioremap(struct pci_device *pci, unsigned long bus_addr, size_t len)
Map PCI bus address as an I/O address.
Definition pcicloud.c:254
static int pcicloud_read_config_dword(struct pci_device *pci, unsigned int where, uint32_t *value)
Read 32-bit dword from PCI configuration space.
Definition pcicloud.c:195
static struct @164334221061242153220350147373067220175352131324 pcicloud
Cached PCI configuration space access API.
static int pcicloud_read_config_byte(struct pci_device *pci, unsigned int where, uint8_t *value)
Read byte from PCI configuration space.
Definition pcicloud.c:165
static struct pci_api * pcicloud_api(struct pci_device *pci)
Find configuration space access API for PCI device.
Definition pcicloud.c:112
static int pcicloud_can_probe(struct pci_device *pci)
Check if PCI bus probing is allowed.
Definition pcicloud.c:151
struct pci_range range
PCI bus:dev.fn address range.
Definition pcicloud.c:40
static void pcicloud_discover(uint32_t busdevfn, struct pci_range *range)
Find next PCI bus:dev.fn address range in system.
Definition pcicloud.c:100
static int pcicloud_write_config_byte(struct pci_device *pci, unsigned int where, uint8_t value)
Write byte to PCI configuration space.
Definition pcicloud.c:210
static int pcicloud_write_config_word(struct pci_device *pci, unsigned int where, uint16_t value)
Write 16-bit word to PCI configuration space.
Definition pcicloud.c:225
Cloud VM PCI configuration space access.
A runtime selectable PCI I/O API.
Definition pci_io.h:166
A PCI device.
Definition pci.h:211
uint32_t busdevfn
Segment, bus, device, and function (bus:dev.fn) number.
Definition pci.h:238
A PCI bus:dev.fn address range.
Definition pci_io.h:23
unsigned int count
Number of bus:dev.fn addresses within this range.
Definition pci_io.h:27
uint32_t start
Starting bus:dev.fn address.
Definition pci_io.h:25
#define table_end(table)
Get end of linker table.
Definition tables.h:309
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386