summaryrefslogtreecommitdiffstats
path: root/lib/pci.h
blob: 71dae3aeb90f2b1217922073a98c578b0584a7b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/*
 *	The PCI Library
 *
 *	Copyright (c) 1997--2024 Martin Mares <mj@ucw.cz>
 *
 *	Can be freely distributed and used under the terms of the GNU GPL v2+
 *
 *	SPDX-License-Identifier: GPL-2.0-or-later
 */

#ifndef _PCI_LIB_H
#define _PCI_LIB_H

#ifndef PCI_CONFIG_H
#include "config.h"
#endif

#include "header.h"
#include "types.h"

#define PCI_LIB_VERSION 0x030d00

#ifndef PCI_ABI
#define PCI_ABI
#endif

/*
 *	PCI Access Structure
 */

struct pci_methods;

enum pci_access_type {
  /* Known access methods, remember to update init.c as well */
  PCI_ACCESS_AUTO,			/* Autodetection */
  PCI_ACCESS_SYS_BUS_PCI,		/* Linux /sys/bus/pci */
  PCI_ACCESS_PROC_BUS_PCI,		/* Linux /proc/bus/pci */
  PCI_ACCESS_I386_TYPE1,		/* i386 ports, type 1 */
  PCI_ACCESS_I386_TYPE2,		/* i386 ports, type 2 */
  PCI_ACCESS_FBSD_DEVICE,		/* FreeBSD /dev/pci */
  PCI_ACCESS_AIX_DEVICE,		/* /dev/pci0, /dev/bus0, etc. */
  PCI_ACCESS_NBSD_LIBPCI,		/* NetBSD libpci */
  PCI_ACCESS_OBSD_DEVICE,		/* OpenBSD /dev/pci */
  PCI_ACCESS_DUMP,			/* Dump file */
  PCI_ACCESS_DARWIN,			/* Darwin */
  PCI_ACCESS_SYLIXOS_DEVICE,		/* SylixOS pci */
  PCI_ACCESS_HURD,			/* GNU/Hurd */
  PCI_ACCESS_WIN32_CFGMGR32,		/* Win32 cfgmgr32.dll */
  PCI_ACCESS_WIN32_KLDBG,		/* Win32 kldbgdrv.sys */
  PCI_ACCESS_WIN32_SYSDBG,		/* Win32 NT SysDbg */
  PCI_ACCESS_MMIO_TYPE1,		/* MMIO ports, type 1 */
  PCI_ACCESS_MMIO_TYPE1_EXT,		/* MMIO ports, type 1 extended */
  PCI_ACCESS_ECAM,			/* PCIe ECAM via /dev/mem */
  PCI_ACCESS_AOS_EXPANSION,		/* AmigaOS Expansion library */
  PCI_ACCESS_MAX
};

struct pci_access {
  /* Options you can change: */
  unsigned int method;			/* Access method */
  int writeable;			/* Open in read/write mode */
  int buscentric;			/* Bus-centric view of the world */

  char *id_file_name;			/* Name of ID list file (use pci_set_name_list_path()) */
  int free_id_name;			/* Set if id_file_name is malloced */
  int numeric_ids;			/* Enforce PCI_LOOKUP_NUMERIC (>1 => PCI_LOOKUP_MIXED) */

  unsigned int id_lookup_mode;		/* pci_lookup_mode flags which are set automatically */
					/* Default: PCI_LOOKUP_CACHE */

  int debugging;			/* Turn on debugging messages */

  /* Functions you can override: */
  void (*error)(char *msg, ...) PCI_PRINTF(1,2) PCI_NONRET;	/* Write error message and quit */
  void (*warning)(char *msg, ...) PCI_PRINTF(1,2);	/* Write a warning message */
  void (*debug)(char *msg, ...) PCI_PRINTF(1,2);	/* Write a debugging message */

  struct pci_dev *devices;		/* Devices found on this bus */

  /* Fields used internally: */
  struct pci_methods *methods;
  struct pci_param *params;
  struct id_entry **id_hash;		/* names.c */
  struct id_bucket *current_id_bucket;
  int id_load_attempted;
  int id_cache_status;			/* 0=not read, 1=read, 2=dirty */
  char *id_cache_name;
  struct udev *id_udev;			/* names-hwdb.c */
  struct udev_hwdb *id_udev_hwdb;
  int fd;				/* proc/sys: fd for config space */
  int fd_rw;				/* proc/sys: fd opened read-write */
  int fd_vpd;				/* sys: fd for VPD */
  struct pci_dev *cached_dev;		/* proc/sys: device the fds are for */
  void *backend_data;			/* Private data of the back end */
};

/* Initialize PCI access */
struct pci_access *pci_alloc(void) PCI_ABI;
void pci_init(struct pci_access *) PCI_ABI;
void pci_cleanup(struct pci_access *) PCI_ABI;

/* Scanning of devices */
void pci_scan_bus(struct pci_access *acc) PCI_ABI;
struct pci_dev *pci_get_dev(struct pci_access *acc, int domain, int bus, int dev, int func) PCI_ABI; /* Raw access to specified device */
void pci_free_dev(struct pci_dev *) PCI_ABI;

/* Names of access methods */
int pci_lookup_method(char *name) PCI_ABI;	/* Returns -1 if not found */
char *pci_get_method_name(int index) PCI_ABI;	/* Returns "" if unavailable, NULL if index out of range */

/*
 *	Named parameters
 */

struct pci_param {
  struct pci_param *next;		/* Please use pci_walk_params() for traversing the list */
  char *param;				/* Name of the parameter */
  char *value;				/* Value of the parameter */
  int value_malloced;			/* used internally */
  char *help;				/* Explanation of the parameter */
};

char *pci_get_param(struct pci_access *acc, char *param) PCI_ABI;
int pci_set_param(struct pci_access *acc, char *param, char *value) PCI_ABI;	/* 0 on success, -1 if no such parameter */
/* To traverse the list, call pci_walk_params repeatedly, first with prev=NULL, and do not modify the parameters during traversal. */
struct pci_param *pci_walk_params(struct pci_access *acc, struct pci_param *prev) PCI_ABI;

/*
 *	Devices
 */

struct pci_dev {
  struct pci_dev *next;			/* Next device in the chain */
  u16 domain_16;			/* 16-bit version of the PCI domain for backward compatibility */
					/* 0xffff if the real domain doesn't fit in 16 bits */
  u8 bus, dev, func;			/* Bus inside domain, device and function */

  /* These fields are set by pci_fill_info() */
  unsigned int known_fields;		/* Set of info fields already known (see pci_fill_info()) */
  u16 vendor_id, device_id;		/* Identity of the device */
  u16 device_class;			/* PCI device class */
  int irq;				/* IRQ number */
  pciaddr_t base_addr[6];		/* Base addresses including flags in lower bits */
  pciaddr_t size[6];			/* Region sizes */
  pciaddr_t rom_base_addr;		/* Expansion ROM base address */
  pciaddr_t rom_size;			/* Expansion ROM size */
  struct pci_cap *first_cap;		/* List of capabilities */
  char *phy_slot;			/* Physical slot */
  char *module_alias;			/* Linux kernel module alias */
  char *label;				/* Device name as exported by BIOS */
  int numa_node;			/* NUMA node */
  pciaddr_t flags[6];			/* PCI_IORESOURCE_* flags for regions */
  pciaddr_t rom_flags;			/* PCI_IORESOURCE_* flags for expansion ROM */
  int domain;				/* PCI domain (host bridge) */
  pciaddr_t bridge_base_addr[4];	/* Bridge base addresses (without flags) */
  pciaddr_t bridge_size[4];		/* Bridge sizes */
  pciaddr_t bridge_flags[4];		/* PCI_IORESOURCE_* flags for bridge addresses */
  u8 prog_if, rev_id;			/* Programming interface for device_class and revision id */
  u16 subsys_vendor_id, subsys_id;	/* Subsystem vendor id and subsystem id */
  struct pci_dev *parent;		/* Parent device, does not have to be always accessible */
  int no_config_access;			/* No access to config space for this device */
  u32 rcd_link_cap;     		/* Link Capabilities register for Restricted CXL Devices */
  u16 rcd_link_status;  		/* Link Status register for RCD */
  u16 rcd_link_ctrl;    		/* Link Control register for RCD */

  /* Fields used internally */
  struct pci_access *access;
  struct pci_methods *methods;
  u8 *cache;				/* Cached config registers */
  int cache_len;
  int hdrtype;				/* Cached low 7 bits of header type, -1 if unknown */
  void *backend_data;			/* Private data for of the back end */
  struct pci_property *properties;	/* A linked list of extra properties */
  struct pci_cap *last_cap;		/* Last capability in the list */
};

#define PCI_ADDR_IO_MASK (~(pciaddr_t) 0x3)
#define PCI_ADDR_MEM_MASK (~(pciaddr_t) 0xf)
#define PCI_ADDR_FLAG_MASK 0xf

/* Access to configuration space */
u8 pci_read_byte(struct pci_dev *, int pos) PCI_ABI;
u16 pci_read_word(struct pci_dev *, int pos) PCI_ABI;
u32 pci_read_long(struct pci_dev *, int pos) PCI_ABI;
int pci_read_vpd(struct pci_dev *d, int pos, u8 *buf, int len) PCI_ABI;
int pci_write_byte(struct pci_dev *, int pos, u8 data) PCI_ABI;
int pci_write_word(struct pci_dev *, int pos, u16 data) PCI_ABI;
int pci_write_long(struct pci_dev *, int pos, u32 data) PCI_ABI;

/* Configuration space as a sequence of bytes (little-endian) */
int pci_read_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;
int pci_write_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;

/*
 * Most device properties take some effort to obtain, so libpci does not
 * initialize them during default bus scan. Instead, you have to call
 * pci_fill_info() with the proper PCI_FILL_xxx constants OR'ed together.
 *
 * Some properties are stored directly in the pci_dev structure.
 * The remaining ones can be accessed through pci_get_string_property().
 *
 * pci_fill_info() returns the current value of pci_dev->known_fields.
 * This is a bit mask of all fields, which were already obtained during
 * the lifetime of the device. This includes fields which are not supported
 * by the particular device -- in that case, the field is left at its default
 * value, which is 0 for integer fields and NULL for pointers. On the other
 * hand, we never consider known fields unsupported by the current back-end;
 * such fields always contain the default value.
 *
 * XXX: flags and the result should be unsigned, but we do not want to break the ABI.
 */

int pci_fill_info(struct pci_dev *, int flags) PCI_ABI;
char *pci_get_string_property(struct pci_dev *d, u32 prop) PCI_ABI;

#define PCI_FILL_IDENT		0x0001		/* vendor and device ID */
#define PCI_FILL_IRQ		0x0002
#define PCI_FILL_BASES		0x0004
#define PCI_FILL_ROM_BASE	0x0008
#define PCI_FILL_SIZES		0x0010
#define PCI_FILL_CLASS		0x0020
#define PCI_FILL_CAPS		0x0040		/* capabilities */
#define PCI_FILL_EXT_CAPS	0x0080		/* extended capabilities */
#define PCI_FILL_PHYS_SLOT	0x0100		/* physical slot (string property) */
#define PCI_FILL_MODULE_ALIAS	0x0200		/* Linux kernel module alias (string property) */
#define PCI_FILL_LABEL		0x0400		/* (string property) */
#define PCI_FILL_NUMA_NODE	0x0800
#define PCI_FILL_IO_FLAGS	0x1000
#define PCI_FILL_DT_NODE	0x2000		/* Device tree node (string property) */
#define PCI_FILL_IOMMU_GROUP	0x4000		/* (string property) */
#define PCI_FILL_BRIDGE_BASES	0x8000
#define PCI_FILL_RESCAN		0x00010000	/* force re-scan of cached properties */
#define PCI_FILL_CLASS_EXT	0x00020000      /* prog_if and rev_id */
#define PCI_FILL_SUBSYS		0x00040000      /* subsys_vendor_id and subsys_id */
#define PCI_FILL_PARENT		0x00080000
#define PCI_FILL_DRIVER		0x00100000      /* OS driver currently in use (string property) */
#define PCI_FILL_RCD_LNK	0x00200000      /* CXL RCD Link status properties (rcd_*) */

void pci_setup_cache(struct pci_dev *, u8 *cache, int len) PCI_ABI;

/*
 *	Capabilities
 */

struct pci_cap {
  struct pci_cap *next;
  u16 id;				/* PCI_CAP_ID_xxx */
  u16 type;				/* PCI_CAP_xxx */
  unsigned int addr;			/* Position in the config space */
};

#define PCI_CAP_NORMAL		1	/* Traditional PCI capabilities */
#define PCI_CAP_EXTENDED	2	/* PCIe extended capabilities */

struct pci_cap *pci_find_cap(struct pci_dev *, unsigned int id, unsigned int type) PCI_ABI;
struct pci_cap *pci_find_cap_nr(struct pci_dev *, unsigned int id, unsigned int type,
                                unsigned int *cap_number) PCI_ABI;

/*
 *	Filters
 */

struct pci_filter {
  int domain, bus, slot, func;			/* -1 = ANY */
  int vendor, device;
  int device_class;
  unsigned int device_class_mask;		/* Which bits of the device_class are compared, default=all */
  int prog_if;
  int rfu[1];
};

void pci_filter_init(struct pci_access *, struct pci_filter *) PCI_ABI;
char *pci_filter_parse_slot(struct pci_filter *, char *) PCI_ABI;
char *pci_filter_parse_id(struct pci_filter *, char *) PCI_ABI;
int pci_filter_match(struct pci_filter *, struct pci_dev *) PCI_ABI;

/*
 *	Conversion of PCI ID's to names (according to the pci.ids file)
 *
 *	Call pci_lookup_name() to identify different types of ID's:
 *
 *	VENDOR				(vendorID) -> vendor
 *	DEVICE				(vendorID, deviceID) -> device
 *	VENDOR | DEVICE			(vendorID, deviceID) -> combined vendor and device
 *	SUBSYSTEM | VENDOR		(subvendorID) -> subsystem vendor
 *	SUBSYSTEM | DEVICE		(vendorID, deviceID, subvendorID, subdevID) -> subsystem device
 *	SUBSYSTEM | VENDOR | DEVICE	(vendorID, deviceID, subvendorID, subdevID) -> combined subsystem v+d
 *	SUBSYSTEM | ...			(-1, -1, subvendorID, subdevID) -> generic subsystem
 *	CLASS				(classID) -> class
 *	PROGIF				(classID, progif) -> programming interface
 */

char *pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...) PCI_ABI;

int pci_load_name_list(struct pci_access *a) PCI_ABI;	/* Called automatically by pci_lookup_*() when needed; returns success */
void pci_free_name_list(struct pci_access *a) PCI_ABI;	/* Called automatically by pci_cleanup() */
void pci_set_name_list_path(struct pci_access *a, char *name, int to_be_freed) PCI_ABI;
void pci_id_cache_flush(struct pci_access *a) PCI_ABI;

enum pci_lookup_mode {
  PCI_LOOKUP_VENDOR = 1,		/* Vendor name (args: vendorID) */
  PCI_LOOKUP_DEVICE = 2,		/* Device name (args: vendorID, deviceID) */
  PCI_LOOKUP_CLASS = 4,			/* Device class (args: classID) */
  PCI_LOOKUP_SUBSYSTEM = 8,
  PCI_LOOKUP_PROGIF = 16,		/* Programming interface (args: classID, prog_if) */
  PCI_LOOKUP_NUMERIC = 0x10000,		/* Want only formatted numbers; default if access->numeric_ids is set */
  PCI_LOOKUP_NO_NUMBERS = 0x20000,	/* Return NULL if not found in the database; default is to print numerically */
  PCI_LOOKUP_MIXED = 0x40000,		/* Include both numbers and names */
  PCI_LOOKUP_NETWORK = 0x80000,		/* Try to resolve unknown ID's by DNS */
  PCI_LOOKUP_SKIP_LOCAL = 0x100000,	/* Do not consult local database */
  PCI_LOOKUP_CACHE = 0x200000,		/* Consult the local cache before using DNS */
  PCI_LOOKUP_REFRESH_CACHE = 0x400000,	/* Forget all previously cached entries, but still allow updating the cache */
  PCI_LOOKUP_NO_HWDB = 0x800000,	/* Do not ask udev's hwdb */
};

#endif