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 
24 FILE_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 */
38 static struct {
39  /** PCI bus:dev.fn address range */
40  struct pci_range range;
41  /** API for this bus:dev.fn address */
42  struct pci_api *api;
43 } pcicloud;
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  */
112 static struct pci_api * pcicloud_api ( struct pci_device *pci ) {
113  struct pci_range *range = &pcicloud.range;
114  struct pci_api *api;
115  uint32_t first;
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  */
151 static 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  */
165 static 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  */
180 static 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  */
195 static 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  */
210 static 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  */
225 static 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  */
240 static int pcicloud_write_config_dword ( struct pci_device *pci,
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  */
254 static 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 PCI_FUNC(busdevfn)
Definition: pci.h:285
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:24
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
#define PCI_BUS(busdevfn)
Definition: pci.h:283
unsigned short uint16_t
Definition: stdint.h:11
typeof() pci_discover * pci_discover
Definition: pci_io.h:168
struct pci_range range
PCI bus:dev.fn address range.
Definition: pcicloud.c:40
typeof() pci_read_config_word * pci_read_config_word
Definition: pci_io.h:170
int pci_can_probe(struct pci_device *pci)
Check if PCI bus probing is allowed.
typeof() pci_write_config_byte * pci_write_config_byte
Definition: pci_io.h:172
typeof() pci_read_config_dword * pci_read_config_dword
Definition: pci_io.h:171
uint32_t first
First block in range.
Definition: pccrr.h:14
static struct pci_api * pcicloud_api(struct pci_device *pci)
Find configuration space access API for PCI device.
Definition: pcicloud.c:112
int pci_write_config_word(struct pci_device *pci, unsigned int where, uint16_t value)
Write 16-bit word to PCI configuration space.
struct pci_api * api
API for this bus:dev.fn address.
Definition: pcicloud.c:42
#define DBGC(...)
Definition: compiler.h:505
long index
Definition: bigint.h:62
int pci_read_config_word(struct pci_device *pci, unsigned int where, uint16_t *value)
Read 16-bit word from PCI configuration space.
#define PCI_APIS
Runtime selectable PCI API table.
Definition: pci_io.h:179
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
static __always_inline void unsigned long bus_addr
Definition: pcibios.h:155
Cloud VM PCI configuration space access.
PROVIDE_PCIAPI(cloud, pci_can_probe, pcicloud_can_probe)
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
uint16_t busdevfn
PCI bus:dev.fn address.
Definition: ena.h:28
void * memcpy(void *dest, const void *src, size_t len) __nonnull
typeof() pci_can_probe * pci_can_probe
Definition: pci_io.h:167
const char * name
Definition: pci_io.h:166
int pci_read_config_dword(struct pci_device *pci, unsigned int where, uint32_t *value)
Read 32-bit dword from PCI configuration space.
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
ring len
Length.
Definition: dwmac.h:231
typeof() pci_write_config_word * pci_write_config_word
Definition: pci_io.h:173
A PCI bus:dev.fn address range.
Definition: pci_io.h:22
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
int pci_write_config_byte(struct pci_device *pci, unsigned int where, uint8_t value)
Write byte to PCI configuration space.
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:311
#define PCI_SLOT(busdevfn)
Definition: pci.h:284
PCI bus.
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
A PCI device.
Definition: pci.h:210
A runtime selectable PCI I/O API.
Definition: pci_io.h:165
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
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:385
typeof() pci_read_config_byte * pci_read_config_byte
Definition: pci_io.h:169
typeof() pci_ioremap * pci_ioremap
Definition: pci_io.h:175
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
unsigned char uint8_t
Definition: stdint.h:10
static int pcicloud_can_probe(struct pci_device *pci)
Check if PCI bus probing is allowed.
Definition: pcicloud.c:151
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
unsigned int uint32_t
Definition: stdint.h:12
unsigned int count
Number of bus:dev.fn addresses within this range.
Definition: pci_io.h:26
void pci_discover(uint32_t busdevfn, struct pci_range *range)
Find next PCI bus:dev.fn address range in system.
uint32_t busdevfn
Segment, bus, device, and function (bus:dev.fn) number.
Definition: pci.h:237
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
int pci_write_config_dword(struct pci_device *pci, unsigned int where, uint32_t value)
Write 32-bit dword to PCI configuration space.
static __always_inline int unsigned int where
Definition: pcibios.h:56
#define table_end(table)
Get end of linker table.
Definition: tables.h:308
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
void * pci_ioremap(struct pci_device *pci, unsigned long bus_addr, size_t len)
Map PCI bus address as an I/O address.
#define PCI_SEG(busdevfn)
Definition: pci.h:282
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
typeof() pci_write_config_dword * pci_write_config_dword
Definition: pci_io.h:174
int pci_read_config_byte(struct pci_device *pci, unsigned int where, uint8_t *value)
Read byte from PCI configuration space.
static struct @8 pcicloud
Cached PCI configuration space access API.