iPXE
Functions | Variables
ecam.c File Reference

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

#include <errno.h>
#include <ipxe/uaccess.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 (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)
 

Variables

static struct ecam_mapping ecam
 Cached mapped ECAM allocation. More...
 
struct pci_api ecam_api = PCIAPI_RUNTIME ( ecam )
 

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_allocation tmp;
50  unsigned int best = 0;
51  unsigned int offset;
52  unsigned int count;
53  unsigned int index;
54  userptr_t mcfg;
57 
58  /* Return empty range on error */
59  range->count = 0;
60 
61  /* Locate MCFG table */
62  mcfg = acpi_table ( ECAM_SIGNATURE, 0 );
63  if ( ! mcfg ) {
64  DBGC ( &ecam, "ECAM found no MCFG table\n" );
65  return -ENOTSUP;
66  }
67 
68  /* Get length of table */
69  copy_from_user ( &length, mcfg,
70  offsetof ( struct ecam_table, acpi.length ),
71  sizeof ( length ) );
72 
73  /* Iterate over allocations */
74  for ( offset = offsetof ( struct ecam_table, alloc ) ;
75  ( offset + sizeof ( tmp ) ) <= le32_to_cpu ( length ) ;
76  offset += sizeof ( tmp ) ) {
77 
78  /* Read allocation */
79  copy_from_user ( &tmp, mcfg, offset, sizeof ( tmp ) );
80  DBGC2 ( &ecam, "ECAM %04x:[%02x-%02x] has base %08llx\n",
81  le16_to_cpu ( tmp.segment ), tmp.start, tmp.end,
82  ( ( unsigned long long ) le64_to_cpu ( tmp.base ) ) );
83  start = PCI_BUSDEVFN ( le16_to_cpu ( tmp.segment ),
84  tmp.start, 0, 0 );
85  count = PCI_BUSDEVFN ( 0, ( tmp.end - tmp.start + 1 ), 0, 0 );
86 
87  /* Check for a matching or new closest allocation */
88  index = ( busdevfn - start );
89  if ( ( index < count ) || ( index > best ) ) {
90  if ( alloc )
91  memcpy ( alloc, &tmp, sizeof ( *alloc ) );
92  range->start = start;
93  range->count = count;
94  best = index;
95  }
96 
97  /* Stop if this range contains the target bus:dev.fn address */
98  if ( index < count )
99  return 0;
100  }
101 
102  return ( best ? 0 : -ENOENT );
103 }
u16 length
Definition: sky2.h:9
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:23
static __always_inline void struct pci_range * range
Definition: efi_pci_api.h:43
#define le32_to_cpu(value)
Definition: byteswap.h:113
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
#define ECAM_SIGNATURE
Enhanced Configuration Access Mechanism table signature.
Definition: ecam.h:19
#define DBGC(...)
Definition: compiler.h:505
userptr_t acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: acpi.c:98
#define ENOENT
No such file or directory.
Definition: errno.h:514
static struct ecam_mapping ecam
Cached mapped ECAM allocation.
Definition: ecam.c:37
#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:53
uint16_t busdevfn
PCI bus:dev.fn address.
Definition: ena.h:28
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition: efi_block.c:65
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
#define PCI_BUSDEVFN(segment, bus, slot, func)
Definition: pci_io.h:28
#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:25
#define DBGC2(...)
Definition: compiler.h:522
An Enhanced Configuration Access Mechanism allocation.
Definition: ecam.h:22
uint16_t count
Number of entries.
Definition: ena.h:22
An Enhanced Configuration Access Mechanism table.
Definition: ecam.h:36
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21
#define le64_to_cpu(value)
Definition: byteswap.h:114
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33

References acpi, acpi_table(), busdevfn, copy_from_user(), count, pci_range::count, DBGC, DBGC2, ecam, ECAM_SIGNATURE, ENOENT, ENOTSUP, index, le16_to_cpu, le32_to_cpu, le64_to_cpu, length, memcpy(), offset, offsetof, PCI_BUSDEVFN, range, start, pci_range::start, and tmp.

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 111 of file ecam.c.

111  {
112 
113  /* Find new range, if any */
115 }
static __always_inline void struct pci_range * range
Definition: efi_pci_api.h:43
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 123 of file ecam.c.

123  {
124  uint64_t base;
125  size_t len;
126  int rc;
127 
128  /* Reuse mapping if possible */
129  if ( ( pci->busdevfn - ecam.range.start ) < ecam.range.count )
130  return ecam.rc;
131 
132  /* Clear any existing mapping */
133  if ( ecam.regs ) {
134  iounmap ( ecam.regs );
135  ecam.regs = NULL;
136  }
137 
138  /* Find allocation for this PCI device */
139  if ( ( rc = ecam_find ( pci->busdevfn, &ecam.range,
140  &ecam.alloc ) ) != 0 ) {
141  DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT ": %s\n",
142  PCI_ARGS ( pci ), strerror ( rc ) );
143  goto err_find;
144  }
145  if ( ecam.range.start > pci->busdevfn ) {
146  DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT "\n",
147  PCI_ARGS ( pci ) );
148  rc = -ENOENT;
149  goto err_find;
150  }
151 
152  /* Map configuration space for this allocation */
154  base += ( ecam.alloc.start * ECAM_SIZE * PCI_BUSDEVFN ( 0, 1, 0, 0 ) );
155  len = ( ecam.range.count * ECAM_SIZE );
156  if ( base != ( ( unsigned long ) base ) ) {
157  DBGC ( &ecam, "ECAM %04x:[%02x-%02x] could not map "
158  "[%08llx,%08llx) outside CPU range\n",
160  ecam.alloc.end, base, ( base + len ) );
161  rc = -ERANGE;
162  goto err_range;
163  }
164  ecam.regs = ioremap ( base, len );
165  if ( ! ecam.regs ) {
166  DBGC ( &ecam, "ECAM %04x:[%02x-%02x] could not map "
167  "[%08llx,%08llx)\n", le16_to_cpu ( ecam.alloc.segment ),
168  ecam.alloc.start, ecam.alloc.end, base, ( base + len ) );
169  rc = -ENODEV;
170  goto err_ioremap;
171  }
172 
173  /* Populate cached mapping */
174  DBGC ( &ecam, "ECAM %04x:[%02x-%02x] mapped [%08llx,%08llx) -> %p\n",
176  ecam.alloc.end, base, ( base + len ), ecam.regs );
177  ecam.rc = 0;
178  return 0;
179 
180  iounmap ( ecam.regs );
181  err_ioremap:
182  err_range:
183  err_find:
184  ecam.rc = rc;
185  return rc;
186 }
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:23
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
static const void * base
Base address.
Definition: crypto.h:335
uint64_t base
Base address.
Definition: ecam.h:24
#define PCI_BUSDEVFN(segment, bus, slot, func)
Definition: pci_io.h:28
#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:307
#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:25
uint32_t busdevfn
Segment, bus, device, and function (bus:dev.fn) number.
Definition: pci.h:233
uint16_t segment
PCI segment number.
Definition: ecam.h:26
uint32_t len
Length.
Definition: ena.h:14
#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:310
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 196 of file ecam.c.

196  {
197  unsigned int where = ECAM_WHERE ( location );
198  unsigned int len = ECAM_LEN ( location );
199  unsigned int index;
200  void *addr;
201  int rc;
202 
203  /* Return all-ones on error */
204  memset ( value, 0xff, len );
205 
206  /* Access configuration space */
207  if ( ( rc = ecam_access ( pci ) ) != 0 )
208  return rc;
209 
210  /* Read from address */
211  index = ( pci->busdevfn - ecam.range.start );
212  addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
213  switch ( len ) {
214  case 4:
215  *( ( uint32_t *) value ) = readl ( addr );
216  break;
217  case 2:
218  *( ( uint16_t *) value ) = readw ( addr );
219  break;
220  case 1:
221  *( ( uint8_t *) value ) = readb ( addr );
222  break;
223  default:
224  assert ( 0 );
225  }
226 
227  return 0;
228 }
static int ecam_access(struct pci_device *pci)
Access configuration space for PCI device.
Definition: ecam.c:123
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:23
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.
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
void * regs
MMIO base address.
Definition: ecam.h:52
u32 addr
Definition: sky2.h:8
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:233
uint32_t len
Length.
Definition: ena.h:14
#define ECAM_SIZE
Enhanced Configuration Access Mechanism per-device size.
Definition: ecam.h:16
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21
#define ECAM_WHERE(location)
Extract offset from ECAM location.
Definition: ecam_io.h:26
static __always_inline int unsigned int where
Definition: ecam_io.h:46
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 238 of file ecam.c.

239  {
240  unsigned int where = ECAM_WHERE ( location );
241  unsigned int len = ECAM_LEN ( location );
242  unsigned int index;
243  void *addr;
244  int rc;
245 
246  /* Access configuration space */
247  if ( ( rc = ecam_access ( pci ) ) != 0 )
248  return rc;
249 
250  /* Write to address */
251  index = ( pci->busdevfn - ecam.range.start );
252  addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
253  switch ( len ) {
254  case 4:
255  writel ( value, addr );
256  break;
257  case 2:
258  writew ( value, addr );
259  break;
260  case 1:
261  writeb ( value, addr );
262  break;
263  default:
264  assert ( 0 );
265  }
266 
267  /* Read from address, to guarantee completion of the write
268  *
269  * PCIe configuration space registers may not have read side
270  * effects. Reading back is therefore always safe to do, and
271  * guarantees that the write has reached the device.
272  */
273  mb();
274  ecam_read ( pci, location, &value );
275 
276  return 0;
277 }
static int ecam_access(struct pci_device *pci)
Access configuration space for PCI device.
Definition: ecam.c:123
uint32_t start
Starting bus:dev.fn address.
Definition: pci_io.h:23
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
struct pci_range range
PCI bus:dev.fn address range.
Definition: ecam.h:50
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)
int ecam_read(struct pci_device *pci, unsigned int location, void *value)
Read from PCI configuration space.
Definition: ecam.c:196
void writel(uint32_t data, volatile uint32_t *io_addr)
Write 32-bit dword to memory-mapped device.
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
void * regs
MMIO base address.
Definition: ecam.h:52
u32 addr
Definition: sky2.h:8
#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:233
uint32_t len
Length.
Definition: ena.h:14
#define writew
Definition: w89c840.c:159
#define ECAM_SIZE
Enhanced Configuration Access Mechanism per-device size.
Definition: ecam.h:16
void mb(void)
Memory barrier.
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21
#define ECAM_WHERE(location)
Extract offset from ECAM location.
Definition: ecam_io.h:26
static __always_inline int unsigned int where
Definition: ecam_io.h:46

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

PROVIDE_PCIAPI ( ecam  ,
pci_discover  ,
ecam_discover   
)

◆ PROVIDE_PCIAPI_INLINE() [1/7]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_read_config_byte   
)

◆ PROVIDE_PCIAPI_INLINE() [2/7]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_read_config_word   
)

◆ PROVIDE_PCIAPI_INLINE() [3/7]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_read_config_dword   
)

◆ PROVIDE_PCIAPI_INLINE() [4/7]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_write_config_byte   
)

◆ PROVIDE_PCIAPI_INLINE() [5/7]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_write_config_word   
)

◆ PROVIDE_PCIAPI_INLINE() [6/7]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_write_config_dword   
)

◆ PROVIDE_PCIAPI_INLINE() [7/7]

PROVIDE_PCIAPI_INLINE ( ecam  ,
pci_ioremap   
)

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

◆ ecam_api

struct pci_api ecam_api = PCIAPI_RUNTIME ( ecam )

Definition at line 288 of file ecam.c.

Referenced by pcicloud_init().