iPXE
Functions | Variables
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. More...
 
static void ecam_discover (uint32_t busdevfn, struct pci_range *range)
 Find next PCI bus:dev.fn address range in system. More...
 
static int ecam_access (struct pci_device *pci)
 Access configuration space for PCI device. More...
 
int ecam_read (struct pci_device *pci, unsigned int location, void *value)
 Read from PCI configuration space. More...
 
int ecam_write (struct pci_device *pci, unsigned int location, unsigned long value)
 Write to PCI configuration space. More...
 
 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. More...
 

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()

static 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 */
61  mcfg = container_of ( acpi_table ( ECAM_SIGNATURE, 0 ),
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 }
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:24
struct pci_range range
PCI bus:dev.fn address range.
Definition: pcicloud.c:40
#define le32_to_cpu(value)
Definition: byteswap.h:113
#define ECAM_SIGNATURE
Enhanced Configuration Access Mechanism table signature.
Definition: ecam.h:19
#define DBGC(...)
Definition: compiler.h:505
long index
Definition: bigint.h:62
#define ENOENT
No such file or directory.
Definition: errno.h:514
static struct ecam_mapping ecam
Cached mapped ECAM allocation.
Definition: ecam.c:37
const struct acpi_header * acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: acpi.c:92
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:24
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
uint32_t start
Starting offset.
Definition: netvsc.h:12
unsigned long tmp
Definition: linux_pci.h:64
uint16_t busdevfn
PCI bus:dev.fn address.
Definition: ena.h:28
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
uint32_t length
Length of table, in bytes, including header.
Definition: acpi.h:183
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition: efi_block.c:66
static unsigned int count
Number of entries.
Definition: dwmac.h:225
struct acpi_header acpi
ACPI header.
Definition: ecam.h:38
#define PCI_BUSDEVFN(segment, bus, slot, func)
Definition: pci_io.h:29
#define le16_to_cpu(value)
Definition: byteswap.h:112
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
#define DBGC2(...)
Definition: compiler.h:522
An Enhanced Configuration Access Mechanism allocation.
Definition: ecam.h:22
An Enhanced Configuration Access Mechanism table.
Definition: ecam.h:36
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:47
#define le64_to_cpu(value)
Definition: byteswap.h:114
struct ecam_allocation alloc[0]
Allocation structures.
Definition: ecam.h:42

References ecam_table::acpi, acpi, acpi_table(), ecam_table::alloc, busdevfn, container_of, pci_range::count, 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, pci_range::start, tmp, and typeof().

Referenced by ecam_access(), and ecam_discover().

◆ ecam_discover()

static 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 }
struct pci_range range
PCI bus:dev.fn address range.
Definition: pcicloud.c:40
uint16_t busdevfn
PCI bus:dev.fn address.
Definition: ena.h:28
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
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321

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

◆ ecam_access()

static 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  {
118  uint64_t base;
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 */
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",
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",
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 }
uint32_t base
Base.
Definition: librm.h:138
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:24
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
struct ecam_allocation alloc
Allocation.
Definition: ecam.h:48
struct pci_range range
PCI bus:dev.fn address range.
Definition: ecam.h:50
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:514
static struct ecam_mapping ecam
Cached mapped ECAM allocation.
Definition: ecam.c:37
unsigned long long uint64_t
Definition: stdint.h:13
ring len
Length.
Definition: dwmac.h:231
uint64_t base
Base address.
Definition: ecam.h:24
#define PCI_BUSDEVFN(segment, bus, slot, func)
Definition: pci_io.h:29
#define ERANGE
Result too large.
Definition: errno.h:639
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
#define PCI_FMT
PCI device debug message format.
Definition: pci.h:311
#define ENODEV
No such device.
Definition: errno.h:509
void * regs
MMIO base address.
Definition: ecam.h:52
int rc
Mapping result.
Definition: ecam.h:54
#define le16_to_cpu(value)
Definition: byteswap.h:112
unsigned int count
Number of bus:dev.fn addresses within this range.
Definition: pci_io.h:26
uint32_t busdevfn
Segment, bus, device, and function (bus:dev.fn) number.
Definition: pci.h:237
uint16_t segment
PCI segment number.
Definition: ecam.h:26
#define ECAM_SIZE
Enhanced Configuration Access Mechanism per-device size.
Definition: ecam.h:16
uint8_t start
Start PCI bus number.
Definition: ecam.h:28
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition: pci.h:314
void iounmap(volatile const void *io_addr)
Unmap I/O address.
uint8_t end
End PCI bus number.
Definition: ecam.h:30
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
void * ioremap(unsigned long bus_addr, size_t len)
Map bus address as an I/O address.
#define le64_to_cpu(value)
Definition: byteswap.h:114
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321

References ecam_mapping::alloc, ecam_allocation::base, base, pci_device::busdevfn, pci_range::count, DBGC, ecam, ecam_find(), ECAM_SIZE, ecam_allocation::end, ENODEV, ENOENT, ERANGE, ioremap(), iounmap(), le16_to_cpu, le64_to_cpu, len, NULL, PCI_ARGS, PCI_BUSDEVFN, PCI_FMT, ecam_mapping::range, ecam_mapping::rc, rc, ecam_mapping::regs, ecam_allocation::segment, pci_range::start, ecam_allocation::start, 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 }
static int ecam_access(struct pci_device *pci)
Access configuration space for PCI device.
Definition: ecam.c:117
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:24
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned short uint16_t
Definition: stdint.h:11
uint8_t readb(volatile uint8_t *io_addr)
Read byte from memory-mapped device.
struct pci_range range
PCI bus:dev.fn address range.
Definition: ecam.h:50
uint16_t readw(volatile uint16_t *io_addr)
Read 16-bit word from memory-mapped device.
uint32_t readl(volatile uint32_t *io_addr)
Read 32-bit dword from memory-mapped device.
long index
Definition: bigint.h:62
static struct ecam_mapping ecam
Cached mapped ECAM allocation.
Definition: ecam.c:37
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
ring len
Length.
Definition: dwmac.h:231
uint32_t addr
Buffer address.
Definition: dwmac.h:20
void * regs
MMIO base address.
Definition: ecam.h:52
unsigned char uint8_t
Definition: stdint.h:10
#define ECAM_LEN(location)
Extract length from ECAM location.
Definition: ecam_io.h:29
unsigned int uint32_t
Definition: stdint.h:12
uint32_t busdevfn
Segment, bus, device, and function (bus:dev.fn) number.
Definition: pci.h:237
#define ECAM_SIZE
Enhanced Configuration Access Mechanism per-device size.
Definition: ecam.h:16
static __always_inline int unsigned int where
Definition: pcibios.h:56
#define ECAM_WHERE(location)
Extract offset from ECAM location.
Definition: ecam_io.h:26
void * memset(void *dest, int character, size_t len) __nonnull

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

Referenced by ecam_write().

◆ 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 }
static int ecam_access(struct pci_device *pci)
Access configuration space for PCI device.
Definition: ecam.c:117
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:24
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
struct pci_range range
PCI bus:dev.fn address range.
Definition: ecam.h:50
long index
Definition: bigint.h:62
static struct ecam_mapping ecam
Cached mapped ECAM allocation.
Definition: ecam.c:37
void writeb(uint8_t data, volatile uint8_t *io_addr)
Write byte to memory-mapped device.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
int ecam_read(struct pci_device *pci, unsigned int location, void *value)
Read from PCI configuration space.
Definition: ecam.c:190
ring len
Length.
Definition: dwmac.h:231
void writel(uint32_t data, volatile uint32_t *io_addr)
Write 32-bit dword to memory-mapped device.
uint32_t addr
Buffer address.
Definition: dwmac.h:20
void * regs
MMIO base address.
Definition: ecam.h:52
#define ECAM_LEN(location)
Extract length from ECAM location.
Definition: ecam_io.h:29
uint32_t busdevfn
Segment, bus, device, and function (bus:dev.fn) number.
Definition: pci.h:237
#define writew
Definition: w89c840.c:159
#define ECAM_SIZE
Enhanced Configuration Access Mechanism per-device size.
Definition: ecam.h:16
static __always_inline int unsigned int where
Definition: pcibios.h:56
void mb(void)
Memory barrier.
#define ECAM_WHERE(location)
Extract offset from ECAM location.
Definition: ecam_io.h:26

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

◆ PROVIDE_PCIAPI_INLINE() [1/8]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_can_probe   
)

◆ PROVIDE_PCIAPI()

PROVIDE_PCIAPI ( ecam  ,
pci_discover  ,
ecam_discover   
)

◆ PROVIDE_PCIAPI_INLINE() [2/8]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_read_config_byte   
)

◆ PROVIDE_PCIAPI_INLINE() [3/8]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_read_config_word   
)

◆ PROVIDE_PCIAPI_INLINE() [4/8]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_read_config_dword   
)

◆ PROVIDE_PCIAPI_INLINE() [5/8]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_write_config_byte   
)

◆ PROVIDE_PCIAPI_INLINE() [6/8]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_write_config_word   
)

◆ PROVIDE_PCIAPI_INLINE() [7/8]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_write_config_dword   
)

◆ PROVIDE_PCIAPI_INLINE() [8/8]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_ioremap   
)

◆ PROVIDE_PCIAPI_RUNTIME()

PROVIDE_PCIAPI_RUNTIME ( ecam  ,
PCIAPI_PRIORITY_ECAM   
)

Variable Documentation

◆ ecam

struct ecam_mapping ecam
static

Cached mapped ECAM allocation.

Definition at line 37 of file ecam.c.

Referenced by ecam_access(), ecam_find(), ecam_read(), and ecam_write().