iPXE
ecam.c File Reference

PCI Enhanced Configuration Access Mechanism (ECAM) More...

#include <string.h>
#include <errno.h>
#include <ipxe/ecam.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static int ecam_find (uint32_t busdevfn, struct pci_range *range, struct ecam_allocation *alloc)
 Find lowest ECAM allocation not below a given PCI bus:dev.fn address.
static void ecam_discover (uint32_t busdevfn, struct pci_range *range)
 Find next PCI bus:dev.fn address range in system.
static int ecam_access (struct pci_device *pci)
 Access configuration space for PCI device.
int ecam_read (struct pci_device *pci, unsigned int location, void *value)
 Read from PCI configuration space.
int ecam_write (struct pci_device *pci, unsigned int location, unsigned long value)
 Write to PCI configuration space.
 PROVIDE_PCIAPI_INLINE (ecam, pci_can_probe)
 PROVIDE_PCIAPI (ecam, pci_discover, ecam_discover)
 PROVIDE_PCIAPI_INLINE (ecam, pci_read_config_byte)
 PROVIDE_PCIAPI_INLINE (ecam, pci_read_config_word)
 PROVIDE_PCIAPI_INLINE (ecam, pci_read_config_dword)
 PROVIDE_PCIAPI_INLINE (ecam, pci_write_config_byte)
 PROVIDE_PCIAPI_INLINE (ecam, pci_write_config_word)
 PROVIDE_PCIAPI_INLINE (ecam, pci_write_config_dword)
 PROVIDE_PCIAPI_INLINE (ecam, pci_ioremap)
 PROVIDE_PCIAPI_RUNTIME (ecam, PCIAPI_PRIORITY_ECAM)

Variables

static struct ecam_mapping ecam
 Cached mapped ECAM allocation.

Detailed Description

PCI Enhanced Configuration Access Mechanism (ECAM)

Definition in file ecam.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ ecam_find()

int ecam_find ( uint32_t busdevfn,
struct pci_range * range,
struct ecam_allocation * alloc )
static

Find lowest ECAM allocation not below a given PCI bus:dev.fn address.

Parameters
busdevfnPCI bus:dev.fn address
rangePCI device address range to fill in
allocECAM allocation to fill in, or NULL
Return values
rcReturn status code

Definition at line 47 of file ecam.c.

48 {
49 struct ecam_table *mcfg;
50 struct ecam_allocation *tmp;
51 unsigned int best = 0;
52 unsigned int count;
53 unsigned int index;
54 unsigned int i;
56
57 /* Return empty range on error */
58 range->count = 0;
59
60 /* Locate MCFG table */
62 struct ecam_table, acpi );
63 if ( ! mcfg ) {
64 DBGC ( &ecam, "ECAM found no MCFG table\n" );
65 return -ENOTSUP;
66 }
67
68 /* Iterate over allocations */
69 for ( i = 0 ; ( offsetof ( typeof ( *mcfg ), alloc[ i + 1 ] ) <=
70 le32_to_cpu ( mcfg->acpi.length ) ) ; i++ ) {
71
72 /* Read allocation */
73 tmp = &mcfg->alloc[i];
74 DBGC2 ( &ecam, "ECAM %04x:[%02x-%02x] has base %08llx\n",
75 le16_to_cpu ( tmp->segment ), tmp->start, tmp->end,
76 ( ( unsigned long long ) le64_to_cpu ( tmp->base ) ) );
77 start = PCI_BUSDEVFN ( le16_to_cpu ( tmp->segment ),
78 tmp->start, 0, 0 );
79 count = PCI_BUSDEVFN ( 0, ( tmp->end - tmp->start + 1 ), 0, 0 );
80
81 /* Check for a matching or new closest allocation */
82 index = ( busdevfn - start );
83 if ( ( index < count ) || ( index > best ) ) {
84 if ( alloc )
85 memcpy ( alloc, tmp, sizeof ( *alloc ) );
86 range->start = start;
87 range->count = count;
88 best = index;
89 }
90
91 /* Stop if this range contains the target bus:dev.fn address */
92 if ( index < count )
93 return 0;
94 }
95
96 return ( best ? 0 : -ENOENT );
97}
const struct acpi_header * acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition acpi.c:93
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
unsigned int uint32_t
Definition stdint.h:12
long index
Definition bigint.h:65
static struct ecam_mapping ecam
Cached mapped ECAM allocation.
Definition ecam.c:37
#define ECAM_SIGNATURE
Enhanced Configuration Access Mechanism table signature.
Definition ecam.h:19
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition efi_block.c:67
uint16_t busdevfn
PCI bus:dev.fn address.
Definition ena.h:17
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
uint32_t start
Starting offset.
Definition netvsc.h:1
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define ENOENT
No such file or directory.
Definition errno.h:515
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define le16_to_cpu(value)
Definition byteswap.h:113
#define le64_to_cpu(value)
Definition byteswap.h:115
#define le32_to_cpu(value)
Definition byteswap.h:114
#define PCI_BUSDEVFN(segment, bus, slot, func)
Definition pci_io.h:30
void * memcpy(void *dest, const void *src, size_t len) __nonnull
unsigned long tmp
Definition linux_pci.h:65
struct pci_range range
PCI bus:dev.fn address range.
Definition pcicloud.c:40
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
uint32_t length
Length of table, in bytes, including header.
Definition acpi.h:184
An Enhanced Configuration Access Mechanism allocation.
Definition ecam.h:22
An Enhanced Configuration Access Mechanism table.
Definition ecam.h:36
struct acpi_header acpi
ACPI header.
Definition ecam.h:38
struct ecam_allocation alloc[0]
Allocation structures.
Definition ecam.h:42

References acpi, ecam_table::acpi, acpi_table(), ecam_table::alloc, busdevfn, container_of, count, DBGC, DBGC2, ecam, ECAM_SIGNATURE, ENOENT, ENOTSUP, index, le16_to_cpu, le32_to_cpu, le64_to_cpu, acpi_header::length, memcpy(), offsetof, PCI_BUSDEVFN, range, start, tmp, and typeof().

Referenced by ecam_access(), and ecam_discover().

◆ ecam_discover()

void ecam_discover ( uint32_t busdevfn,
struct pci_range * range )
static

Find next PCI bus:dev.fn address range in system.

Parameters
busdevfnStarting PCI bus:dev.fn address
rangePCI bus:dev.fn address range to fill in

Definition at line 105 of file ecam.c.

105 {
106
107 /* Find new range, if any */
109}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
static int ecam_find(uint32_t busdevfn, struct pci_range *range, struct ecam_allocation *alloc)
Find lowest ECAM allocation not below a given PCI bus:dev.fn address.
Definition ecam.c:47

References busdevfn, ecam_find(), NULL, and range.

Referenced by PROVIDE_PCIAPI().

◆ ecam_access()

int ecam_access ( struct pci_device * pci)
static

Access configuration space for PCI device.

Parameters
pciPCI device
Return values
rcReturn status code

Definition at line 117 of file ecam.c.

117 {
119 size_t len;
120 int rc;
121
122 /* Reuse mapping if possible */
123 if ( ( pci->busdevfn - ecam.range.start ) < ecam.range.count )
124 return ecam.rc;
125
126 /* Clear any existing mapping */
127 if ( ecam.regs ) {
128 iounmap ( ecam.regs );
129 ecam.regs = NULL;
130 }
131
132 /* Find allocation for this PCI device */
133 if ( ( rc = ecam_find ( pci->busdevfn, &ecam.range,
134 &ecam.alloc ) ) != 0 ) {
135 DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT ": %s\n",
136 PCI_ARGS ( pci ), strerror ( rc ) );
137 goto err_find;
138 }
139 if ( ecam.range.start > pci->busdevfn ) {
140 DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT "\n",
141 PCI_ARGS ( pci ) );
142 rc = -ENOENT;
143 goto err_find;
144 }
145
146 /* Map configuration space for this allocation */
147 base = le64_to_cpu ( ecam.alloc.base );
148 base += ( ecam.alloc.start * ECAM_SIZE * PCI_BUSDEVFN ( 0, 1, 0, 0 ) );
149 len = ( ecam.range.count * ECAM_SIZE );
150 if ( base != ( ( unsigned long ) base ) ) {
151 DBGC ( &ecam, "ECAM %04x:[%02x-%02x] could not map "
152 "[%08llx,%08llx) outside CPU range\n",
153 le16_to_cpu ( ecam.alloc.segment ), ecam.alloc.start,
154 ecam.alloc.end, base, ( base + len ) );
155 rc = -ERANGE;
156 goto err_range;
157 }
158 ecam.regs = ioremap ( base, len );
159 if ( ! ecam.regs ) {
160 DBGC ( &ecam, "ECAM %04x:[%02x-%02x] could not map "
161 "[%08llx,%08llx)\n", le16_to_cpu ( ecam.alloc.segment ),
162 ecam.alloc.start, ecam.alloc.end, base, ( base + len ) );
163 rc = -ENODEV;
164 goto err_ioremap;
165 }
166
167 /* Populate cached mapping */
168 DBGC ( &ecam, "ECAM %04x:[%02x-%02x] mapped [%08llx,%08llx) -> %p\n",
169 le16_to_cpu ( ecam.alloc.segment ), ecam.alloc.start,
170 ecam.alloc.end, base, ( base + len ), ecam.regs );
171 ecam.rc = 0;
172 return 0;
173
174 iounmap ( ecam.regs );
175 err_ioremap:
176 err_range:
177 err_find:
178 ecam.rc = rc;
179 return rc;
180}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned long long uint64_t
Definition stdint.h:13
ring len
Length.
Definition dwmac.h:226
#define ECAM_SIZE
Enhanced Configuration Access Mechanism per-device size.
Definition ecam.h:16
#define ERANGE
Result too large.
Definition errno.h:640
#define ENODEV
No such device.
Definition errno.h:510
void * ioremap(unsigned long bus_addr, size_t len)
Map bus address as an I/O address.
void iounmap(volatile const void *io_addr)
Unmap I/O address.
uint32_t base
Base.
Definition librm.h:3
#define PCI_FMT
PCI device debug message format.
Definition pci.h:312
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition pci.h:315
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
uint32_t busdevfn
Segment, bus, device, and function (bus:dev.fn) number.
Definition pci.h:238

References base, pci_device::busdevfn, DBGC, ecam, ecam_find(), ECAM_SIZE, ENODEV, ENOENT, ERANGE, ioremap(), iounmap(), le16_to_cpu, le64_to_cpu, len, NULL, PCI_ARGS, PCI_BUSDEVFN, PCI_FMT, rc, and strerror().

Referenced by ecam_read(), and ecam_write().

◆ ecam_read()

int ecam_read ( struct pci_device * pci,
unsigned int location,
void * value )

Read from PCI configuration space.

Parameters
pciPCI device
locationOffset and length within PCI configuration space
valueValue read
Return values
rcReturn status code

Definition at line 190 of file ecam.c.

190 {
191 unsigned int where = ECAM_WHERE ( location );
192 unsigned int len = ECAM_LEN ( location );
193 unsigned int index;
194 void *addr;
195 int rc;
196
197 /* Return all-ones on error */
198 memset ( value, 0xff, len );
199
200 /* Access configuration space */
201 if ( ( rc = ecam_access ( pci ) ) != 0 )
202 return rc;
203
204 /* Read from address */
205 index = ( pci->busdevfn - ecam.range.start );
206 addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
207 switch ( len ) {
208 case 4:
209 *( ( uint32_t *) value ) = readl ( addr );
210 break;
211 case 2:
212 *( ( uint16_t *) value ) = readw ( addr );
213 break;
214 case 1:
215 *( ( uint8_t *) value ) = readb ( addr );
216 break;
217 default:
218 assert ( 0 );
219 }
220
221 return 0;
222}
pseudo_bit_t value[0x00020]
Definition arbel.h:2
unsigned short uint16_t
Definition stdint.h:11
unsigned char uint8_t
Definition stdint.h:10
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
uint32_t addr
Buffer address.
Definition dwmac.h:9
static int ecam_access(struct pci_device *pci)
Access configuration space for PCI device.
Definition ecam.c:117
#define ECAM_WHERE(location)
Extract offset from ECAM location.
Definition ecam_io.h:27
#define ECAM_LEN(location)
Extract length from ECAM location.
Definition ecam_io.h:30
void * memset(void *dest, int character, size_t len) __nonnull
static __always_inline int unsigned int where
Definition pcibios.h:57
#define readl
Definition w89c840.c:157
#define readb
Definition w89c840.c:155
#define readw
Definition w89c840.c:156

References addr, assert, pci_device::busdevfn, ecam, ecam_access(), ECAM_LEN, ECAM_SIZE, ECAM_WHERE, index, len, memset(), rc, readb, readl, readw, value, and where.

Referenced by ecam_write(), PCIAPI_INLINE(), and PCIAPI_INLINE().

◆ ecam_write()

int ecam_write ( struct pci_device * pci,
unsigned int location,
unsigned long value )

Write to PCI configuration space.

Parameters
pciPCI device
locationOffset and length within PCI configuration space
valueValue to write
Return values
rcReturn status code

Definition at line 232 of file ecam.c.

233 {
234 unsigned int where = ECAM_WHERE ( location );
235 unsigned int len = ECAM_LEN ( location );
236 unsigned int index;
237 void *addr;
238 int rc;
239
240 /* Access configuration space */
241 if ( ( rc = ecam_access ( pci ) ) != 0 )
242 return rc;
243
244 /* Write to address */
245 index = ( pci->busdevfn - ecam.range.start );
246 addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
247 switch ( len ) {
248 case 4:
249 writel ( value, addr );
250 break;
251 case 2:
252 writew ( value, addr );
253 break;
254 case 1:
255 writeb ( value, addr );
256 break;
257 default:
258 assert ( 0 );
259 }
260
261 /* Read from address, to guarantee completion of the write
262 *
263 * PCIe configuration space registers may not have read side
264 * effects. Reading back is therefore always safe to do, and
265 * guarantees that the write has reached the device.
266 */
267 mb();
268 ecam_read ( pci, location, &value );
269
270 return 0;
271}
int ecam_read(struct pci_device *pci, unsigned int location, void *value)
Read from PCI configuration space.
Definition ecam.c:190
void mb(void)
Memory barrier.
#define writel
Definition w89c840.c:160
#define writew
Definition w89c840.c:159
#define writeb
Definition w89c840.c:158

References addr, assert, pci_device::busdevfn, ecam, ecam_access(), ECAM_LEN, ecam_read(), ECAM_SIZE, ECAM_WHERE, index, len, mb(), rc, value, where, writeb, writel, and writew.

Referenced by PCIAPI_INLINE(), PCIAPI_INLINE(), and PCIAPI_INLINE().

◆ PROVIDE_PCIAPI_INLINE() [1/8]

PROVIDE_PCIAPI_INLINE ( ecam ,
pci_can_probe  )

References ecam, and pci_can_probe().

◆ PROVIDE_PCIAPI()

PROVIDE_PCIAPI ( ecam ,
pci_discover ,
ecam_discover  )

References ecam, ecam_discover(), and pci_discover().

◆ PROVIDE_PCIAPI_INLINE() [2/8]

PROVIDE_PCIAPI_INLINE ( ecam ,
pci_read_config_byte  )

References ecam, and pci_read_config_byte().

◆ PROVIDE_PCIAPI_INLINE() [3/8]

PROVIDE_PCIAPI_INLINE ( ecam ,
pci_read_config_word  )

References ecam, and pci_read_config_word().

◆ PROVIDE_PCIAPI_INLINE() [4/8]

PROVIDE_PCIAPI_INLINE ( ecam ,
pci_read_config_dword  )

References ecam, and pci_read_config_dword().

◆ PROVIDE_PCIAPI_INLINE() [5/8]

PROVIDE_PCIAPI_INLINE ( ecam ,
pci_write_config_byte  )

References ecam, and pci_write_config_byte().

◆ PROVIDE_PCIAPI_INLINE() [6/8]

PROVIDE_PCIAPI_INLINE ( ecam ,
pci_write_config_word  )

References ecam, and pci_write_config_word().

◆ PROVIDE_PCIAPI_INLINE() [7/8]

PROVIDE_PCIAPI_INLINE ( ecam ,
pci_write_config_dword  )

References ecam, and pci_write_config_dword().

◆ PROVIDE_PCIAPI_INLINE() [8/8]

PROVIDE_PCIAPI_INLINE ( ecam ,
pci_ioremap  )

References ecam, and pci_ioremap().

◆ PROVIDE_PCIAPI_RUNTIME()

PROVIDE_PCIAPI_RUNTIME ( ecam ,
PCIAPI_PRIORITY_ECAM  )

References ecam, and PCIAPI_PRIORITY_ECAM.

Variable Documentation

◆ ecam