AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
pci.c File Reference

The PCI bus: finding devices, and reading and writing their configuration space. More...

#include <core/system.h>
#include <core/module.h>
#include <core/arch.h>
#include <dev/pci.h>
#include <cpu/io.h>
#include <mm/mm.h>

Go to the source code of this file.

Macros

#define PCI_COMMAND   0x04
#define PCI_COMMAND_IO   0x0001
#define PCI_COMMAND_MEMORY   0x0002
#define PCI_COMMAND_MASTER   0x0004
#define PCI_INTERRUPT_LINE   0x3C
#define PCI_INTERRUPT_PIN   0x3D
#define ALIGN_TO(x, a)
#define PCI_STATUS   0x06
#define PCI_STATUS_CAP_LIST   0x10
#define PCI_CAPABILITIES   0x34
#define PCI_COMMAND_INTX_OFF   0x400
#define MSI_CTRL   2
#define MSI_ADDR   4
#define MSI_CTRL_ENABLE   0x0001
#define MSI_CTRL_MME   0x0070
#define MSI_CTRL_64BIT   0x0080

Functions

static uint32_t pci_read_dword (uint8_t bus, uint8_t dev, uint8_t func, uint16_t reg)
 Reads a 32-bit configuration register, or returns all ones (no device) if there is no host bridge.
static void pci_write_dword (uint8_t bus, uint8_t dev, uint8_t func, uint16_t reg, uint32_t val)
 Writes a 32-bit configuration register, if there is a host bridge.
static uint16_t get_vendor_id (uint8_t bus, uint8_t dev, uint8_t func)
 Returns a function's vendor ID: all ones if there's no function.
static uint16_t get_device_id (uint8_t bus, uint8_t dev, uint8_t func)
 Returns a function's device ID.
static uint8_t get_class_code (uint8_t bus, uint8_t dev, uint8_t func)
 Returns a function's class code.
static uint8_t get_subclass_code (uint8_t bus, uint8_t dev, uint8_t func)
 Returns a function's subclass code.
static uint8_t get_header_type (uint8_t bus, uint8_t dev, uint8_t func)
 Returns a function's header type: bit 7 set for a device with several functions, the rest 0 for a device and 1 for a bridge.
static uint32_t get_bar (uint8_t bus, uint8_t dev, uint8_t func, uint8_t id)
 Returns a function's base address register id, as it is.
int pci_device_scan (uint16_t vendor_id, uint16_t device_id, struct pci_dev *ref)
 Finds a device by its vendor and device IDs, on bus 0.
uint8_t pci_reg8_read (struct pci_dev *dev, uint8_t off)
 Reads an 8-bit configuration register.
uint16_t pci_reg16_read (struct pci_dev *dev, uint8_t off)
 Reads a 16-bit configuration register.
uint32_t pci_reg32_read (struct pci_dev *dev, uint8_t off)
 Reads a 32-bit configuration register.
void pci_reg8_write (struct pci_dev *dev, uint8_t off, uint8_t val)
 Writes an 8-bit configuration register: the 32-bit register it's in is read, changed and written back.
void pci_reg16_write (struct pci_dev *dev, uint8_t off, uint16_t val)
 Writes a 16-bit configuration register: the 32-bit register it's in is read, changed and written back.
void pci_reg32_write (struct pci_dev *dev, uint8_t off, uint32_t val)
 Writes a 32-bit configuration register.
static void scan_device (uint8_t bus, uint8_t dev)
 Prints the functions of a device, for debugging.
static void scan_bus (uint8_t bus)
 Prints the devices of a bus, for debugging (nothing calls it).
int pci_prope ()
 The PCI module's initialization, which has nothing to do: drivers find their devices themselves.
int pci_scan_device (uint8_t class, uint8_t subclass, struct pci_dev *_dev, size_t nr)
 Finds the functions of a class and subclass, on bus 0.
uint32_t pci_read_bar (struct pci_dev *dev, uint8_t id)
 Reads a base address register as it is, flag bits included.
int pci_bar (struct pci_dev *dev, int id, struct pci_bar *bar)
 Reads a base address register: what it decodes (memory or ports), its address, and its size.
void pci_enable (struct pci_dev *dev)
 Turns a function's memory and port decoding on, and bus mastering, so that it can do DMA.
int pci_irq (struct pci_dev *dev)
 Finds the IRQ that a function's interrupt pin comes to.
static void pci_assign (void)
 Assigns addresses to the BARs that no firmware assigned, on bus 0's devices: each BAR in the host's window for its kind (memory or ports), aligned to its size.
int pci_host_set (struct pci_host *h)
 Sets the platform's host bridge, from platform_init().
uint8_t pci_cap_find (struct pci_dev *dev, uint8_t id)
 Finds one of a function's capabilities.
int pci_msi_enable (struct pci_dev *dev, irq_handler_t handler, void *arg)
 Has a function send its interrupts as messages (MSI) instead of on its interrupt line: one message, for an IRQ that goes to handler.

Variables

static struct pci_host * host
struct dev pcidev

Detailed Description

The PCI bus: finding devices, and reading and writing their configuration space.

Every PCI function has a configuration space: who made it (vendor and device IDs), what it is (class and subclass), which memory and ports it decodes (its base address registers, BARs), its interrupt, and a list of capabilities. How that space is reached is the platform's: the host bridge (struct pci_host) that platform_init() gives pci_host_set(), with configuration mechanism #1 (conf1.c) or ECAM (ecam.c). Only bus 0 is scanned. See docs/kernel/devices.md.

Definition in file pci.c.

Macro Definition Documentation

◆ ALIGN_TO

#define ALIGN_TO ( x,
a )
Value:
(((x) + (a) - 1) & ~((uint64_t) (a) - 1))
unsigned long long int uint64_t
Definition stddef.h:23

Definition at line 380 of file pci.c.

Referenced by pci_assign().

◆ MSI_ADDR

#define MSI_ADDR   4

Definition at line 500 of file pci.c.

Referenced by pci_msi_enable().

◆ MSI_CTRL

#define MSI_CTRL   2

Definition at line 499 of file pci.c.

Referenced by pci_msi_enable().

◆ MSI_CTRL_64BIT

#define MSI_CTRL_64BIT   0x0080

Definition at line 503 of file pci.c.

Referenced by pci_msi_enable().

◆ MSI_CTRL_ENABLE

#define MSI_CTRL_ENABLE   0x0001

Definition at line 501 of file pci.c.

Referenced by pci_msi_enable().

◆ MSI_CTRL_MME

#define MSI_CTRL_MME   0x0070

Definition at line 502 of file pci.c.

Referenced by pci_msi_enable().

◆ PCI_CAPABILITIES

#define PCI_CAPABILITIES   0x34

Definition at line 467 of file pci.c.

Referenced by pci_cap_find().

◆ PCI_COMMAND

#define PCI_COMMAND   0x04

Definition at line 290 of file pci.c.

Referenced by pci_bar(), pci_enable(), and pci_msi_enable().

◆ PCI_COMMAND_INTX_OFF

#define PCI_COMMAND_INTX_OFF   0x400

Definition at line 468 of file pci.c.

Referenced by pci_msi_enable().

◆ PCI_COMMAND_IO

#define PCI_COMMAND_IO   0x0001

Definition at line 291 of file pci.c.

Referenced by pci_bar(), and pci_enable().

◆ PCI_COMMAND_MASTER

#define PCI_COMMAND_MASTER   0x0004

Definition at line 293 of file pci.c.

Referenced by pci_enable().

◆ PCI_COMMAND_MEMORY

#define PCI_COMMAND_MEMORY   0x0002

Definition at line 292 of file pci.c.

Referenced by pci_bar(), and pci_enable().

◆ PCI_INTERRUPT_LINE

#define PCI_INTERRUPT_LINE   0x3C

Definition at line 294 of file pci.c.

Referenced by pci_irq().

◆ PCI_INTERRUPT_PIN

#define PCI_INTERRUPT_PIN   0x3D

Definition at line 356 of file pci.c.

Referenced by pci_irq().

◆ PCI_STATUS

#define PCI_STATUS   0x06

Definition at line 465 of file pci.c.

Referenced by pci_cap_find().

◆ PCI_STATUS_CAP_LIST

#define PCI_STATUS_CAP_LIST   0x10

Definition at line 466 of file pci.c.

Referenced by pci_cap_find().

Function Documentation

◆ get_bar()

uint32_t get_bar ( uint8_t bus,
uint8_t dev,
uint8_t func,
uint8_t id )
inlinestatic

Returns a function's base address register id, as it is.

Definition at line 74 of file pci.c.

References pci_dev::bus, pci_dev::func, get_bar(), and pci_read_dword().

Referenced by get_bar().

◆ get_class_code()

uint8_t get_class_code ( uint8_t bus,
uint8_t dev,
uint8_t func )
inlinestatic

Returns a function's class code.

Definition at line 55 of file pci.c.

References pci_dev::bus, pci_dev::func, get_class_code(), and pci_read_dword().

Referenced by get_class_code(), pci_scan_device(), and scan_device().

◆ get_device_id()

uint16_t get_device_id ( uint8_t bus,
uint8_t dev,
uint8_t func )
inlinestatic

Returns a function's device ID.

Definition at line 49 of file pci.c.

References pci_dev::bus, pci_dev::func, get_device_id(), and pci_read_dword().

Referenced by get_device_id(), pci_device_scan(), and scan_device().

◆ get_header_type()

uint8_t get_header_type ( uint8_t bus,
uint8_t dev,
uint8_t func )
inlinestatic

Returns a function's header type: bit 7 set for a device with several functions, the rest 0 for a device and 1 for a bridge.

Definition at line 68 of file pci.c.

References pci_dev::bus, pci_dev::func, get_header_type(), and pci_read_dword().

Referenced by get_header_type(), and pci_assign().

◆ get_subclass_code()

uint8_t get_subclass_code ( uint8_t bus,
uint8_t dev,
uint8_t func )
inlinestatic

Returns a function's subclass code.

Definition at line 61 of file pci.c.

References pci_dev::bus, pci_dev::func, get_subclass_code(), and pci_read_dword().

Referenced by get_subclass_code(), pci_scan_device(), and scan_device().

◆ get_vendor_id()

uint16_t get_vendor_id ( uint8_t bus,
uint8_t dev,
uint8_t func )
inlinestatic

Returns a function's vendor ID: all ones if there's no function.

Definition at line 43 of file pci.c.

References pci_dev::bus, pci_dev::func, get_vendor_id(), and pci_read_dword().

Referenced by get_vendor_id(), pci_assign(), pci_device_scan(), pci_scan_device(), and scan_device().

◆ pci_assign()

void pci_assign ( void )
static

Assigns addresses to the BARs that no firmware assigned, on bus 0's devices: each BAR in the host's window for its kind (memory or ports), aligned to its size.

The addresses are the bus's.

Definition at line 385 of file pci.c.

References pci_bar::addr, ALIGN_TO, pci_dev::func, get_header_type(), get_vendor_id(), host, pci_bar::io, pci_host::io_base, pci_host::io_size, pci_host::mem_base, pci_host::mem_size, pci_assign(), pci_reg32_read(), pci_reg32_write(), printk(), and pci_bar::size.

Referenced by pci_assign(), and pci_host_set().

◆ pci_bar()

int pci_bar ( struct pci_dev * dev,
int id,
struct pci_bar * bar )

Reads a base address register: what it decodes (memory or ports), its address, and its size.

The size is found by writing all ones to the register and reading back what the device kept, with decoding turned off meanwhile. A 64-bit memory BAR uses the next register too.

Parameters
devthe function
idthe BAR's number, 0 to 5
barset to what the BAR decodes
Returns
0, or -1 if the BAR decodes nothing

Definition at line 307 of file pci.c.

References pci_bar::addr, pci_bar::io, PCI_COMMAND, PCI_COMMAND_IO, PCI_COMMAND_MEMORY, pci_reg16_read(), pci_reg16_write(), pci_reg32_read(), pci_reg32_write(), and pci_bar::size.

◆ pci_cap_find()

uint8_t pci_cap_find ( struct pci_dev * dev,
uint8_t id )

Finds one of a function's capabilities.

Parameters
devthe function
idthe capability (PCI_CAP_*)
Returns
the capability's offset in the configuration space, or 0 if the function doesn't have it

Definition at line 478 of file pci.c.

References pci_cap_find(), PCI_CAPABILITIES, pci_reg16_read(), pci_reg8_read(), PCI_STATUS, and PCI_STATUS_CAP_LIST.

Referenced by pci_cap_find(), and pci_msi_enable().

◆ pci_device_scan()

int pci_device_scan ( uint16_t vendor_id,
uint16_t device_id,
struct pci_dev * ref )

Finds a device by its vendor and device IDs, on bus 0.

Parameters
vendor_idthe vendor ID
device_idthe device ID
refif not NULL, set to the first function found
Returns
0 if one was found, -1 if not

Definition at line 87 of file pci.c.

References pci_dev::bus, pci_dev::dev, pci_dev::func, get_device_id(), get_vendor_id(), and pci_device_scan().

Referenced by e1000_probe(), and pci_device_scan().

◆ pci_enable()

void pci_enable ( struct pci_dev * dev)

Turns a function's memory and port decoding on, and bus mastering, so that it can do DMA.

Parameters
devthe function

Definition at line 349 of file pci.c.

References PCI_COMMAND, PCI_COMMAND_IO, PCI_COMMAND_MASTER, PCI_COMMAND_MEMORY, pci_enable(), pci_reg16_read(), and pci_reg16_write().

Referenced by e1000_probe(), and pci_enable().

◆ pci_host_set()

int pci_host_set ( struct pci_host * h)

Sets the platform's host bridge, from platform_init().

Its configuration space is mapped if it is memory (ECAM), and the BARs no firmware assigned get addresses in its windows.

Parameters
hthe host bridge
Returns
0, or -ENOMEM if its configuration space couldn't be mapped

Definition at line 443 of file pci.c.

References ioaddr::addr, arch_mmio_map(), pci_host::config, host, pci_host::io_size, IOADDR_PORT, pci_host::mem_size, pci_host::name, pci_assign(), pci_host_set(), printk(), pci_host::size, and ioaddr::type.

Referenced by pci_host_set(), platform_init(), and x86_pc_pci_init().

◆ pci_irq()

int pci_irq ( struct pci_dev * dev)

Finds the IRQ that a function's interrupt pin comes to.

If the host bridge says which IRQs INTA# to INTD# come to, the pin is swizzled by the device's slot, as a bridge's interrupt map does (INTA# of slot 1 is INTB#). Otherwise it is the interrupt line that the firmware wrote.

Parameters
devthe function
Returns
the IRQ, or -1 if the function has no interrupt pin

Definition at line 367 of file pci.c.

References host, pci_host::irq, pci_host::nirq, PCI_INTERRUPT_LINE, PCI_INTERRUPT_PIN, pci_irq(), and pci_reg8_read().

Referenced by ata_probe(), e1000_probe(), and pci_irq().

◆ pci_msi_enable()

int pci_msi_enable ( struct pci_dev * dev,
irq_handler_t handler,
void * arg )

Has a function send its interrupts as messages (MSI) instead of on its interrupt line: one message, for an IRQ that goes to handler.

Its interrupt line (INTx) is turned off. If MSI isn't possible, the caller uses the line instead.

Parameters
devthe function
handlerthe interrupt's handler
argthe handler's argument
Returns
the IRQ, -ENODEV if the function or the architecture has no MSI, or another negative errno

Definition at line 517 of file pci.c.

References pci_bar::addr, arch_msi_alloc(), MSI_ADDR, MSI_CTRL, MSI_CTRL_64BIT, MSI_CTRL_ENABLE, MSI_CTRL_MME, pci_cap_find(), PCI_CAP_MSI, PCI_COMMAND, PCI_COMMAND_INTX_OFF, pci_msi_enable(), pci_reg16_read(), pci_reg16_write(), and pci_reg32_write().

Referenced by e1000_probe(), and pci_msi_enable().

◆ pci_prope()

int pci_prope ( )

The PCI module's initialization, which has nothing to do: drivers find their devices themselves.

Returns
0

Definition at line 220 of file pci.c.

References pci_prope().

Referenced by pci_prope().

◆ pci_read_bar()

uint32_t pci_read_bar ( struct pci_dev * dev,
uint8_t id )

Reads a base address register as it is, flag bits included.

Parameters
devthe function
idthe BAR's number, 0 to 5
Returns
the register's value

Definition at line 285 of file pci.c.

References pci_read_bar(), and pci_read_dword().

Referenced by ata_probe(), and pci_read_bar().

◆ pci_read_dword()

uint32_t pci_read_dword ( uint8_t bus,
uint8_t dev,
uint8_t func,
uint16_t reg )
inlinestatic

Reads a 32-bit configuration register, or returns all ones (no device) if there is no host bridge.

Definition at line 27 of file pci.c.

References pci_dev::bus, pci_dev::func, host, pci_read_dword(), and pci_host::read.

Referenced by get_bar(), get_class_code(), get_device_id(), get_header_type(), get_subclass_code(), get_vendor_id(), pci_read_bar(), pci_read_dword(), pci_reg16_read(), pci_reg16_write(), pci_reg32_read(), pci_reg8_read(), and pci_reg8_write().

◆ pci_reg16_read()

uint16_t pci_reg16_read ( struct pci_dev * dev,
uint8_t off )

Reads a 16-bit configuration register.

Parameters
devthe function
offthe register's offset, a multiple of 2
Returns
its value

Definition at line 130 of file pci.c.

References pci_read_dword(), and pci_reg16_read().

Referenced by ata_probe(), pci_bar(), pci_cap_find(), pci_enable(), pci_msi_enable(), and pci_reg16_read().

◆ pci_reg16_write()

void pci_reg16_write ( struct pci_dev * dev,
uint8_t off,
uint16_t val )

Writes a 16-bit configuration register: the 32-bit register it's in is read, changed and written back.

Parameters
devthe function
offthe register's offset, a multiple of 2
valthe value to write

Definition at line 170 of file pci.c.

References pci_read_dword(), pci_reg16_write(), and pci_write_dword().

Referenced by ata_probe(), pci_bar(), pci_enable(), pci_msi_enable(), and pci_reg16_write().

◆ pci_reg32_read()

uint32_t pci_reg32_read ( struct pci_dev * dev,
uint8_t off )

Reads a 32-bit configuration register.

Parameters
devthe function
offthe register's offset, a multiple of 4
Returns
its value

Definition at line 142 of file pci.c.

References pci_read_dword(), and pci_reg32_read().

Referenced by pci_assign(), pci_bar(), and pci_reg32_read().

◆ pci_reg32_write()

void pci_reg32_write ( struct pci_dev * dev,
uint8_t off,
uint32_t val )

Writes a 32-bit configuration register.

Parameters
devthe function
offthe register's offset, a multiple of 4
valthe value to write

Definition at line 184 of file pci.c.

References pci_reg32_write(), and pci_write_dword().

Referenced by pci_assign(), pci_bar(), pci_msi_enable(), and pci_reg32_write().

◆ pci_reg8_read()

uint8_t pci_reg8_read ( struct pci_dev * dev,
uint8_t off )

Reads an 8-bit configuration register.

Parameters
devthe function
offthe register's offset
Returns
its value

Definition at line 118 of file pci.c.

References pci_read_dword(), and pci_reg8_read().

Referenced by pci_cap_find(), pci_irq(), and pci_reg8_read().

◆ pci_reg8_write()

void pci_reg8_write ( struct pci_dev * dev,
uint8_t off,
uint8_t val )

Writes an 8-bit configuration register: the 32-bit register it's in is read, changed and written back.

Parameters
devthe function
offthe register's offset
valthe value to write

Definition at line 155 of file pci.c.

References pci_read_dword(), pci_reg8_write(), and pci_write_dword().

Referenced by pci_reg8_write().

◆ pci_scan_device()

int pci_scan_device ( uint8_t class,
uint8_t subclass,
struct pci_dev * _dev,
size_t nr )

Finds the functions of a class and subclass, on bus 0.

Parameters
classthe class code
subclassthe subclass code
_devset to the functions found
nrhow many _dev can hold
Returns
how many were found, at most nr

Definition at line 244 of file pci.c.

References pci_dev::bus, pci_dev::dev, pci_dev::func, get_class_code(), get_subclass_code(), get_vendor_id(), and pci_scan_device().

Referenced by ata_probe(), and pci_scan_device().

◆ pci_write_dword()

void pci_write_dword ( uint8_t bus,
uint8_t dev,
uint8_t func,
uint16_t reg,
uint32_t val )
inlinestatic

Writes a 32-bit configuration register, if there is a host bridge.

Definition at line 34 of file pci.c.

References pci_dev::bus, pci_dev::func, host, pci_write_dword(), and pci_host::write.

Referenced by pci_reg16_write(), pci_reg32_write(), pci_reg8_write(), and pci_write_dword().

◆ scan_bus()

void scan_bus ( uint8_t bus)
static

Prints the devices of a bus, for debugging (nothing calls it).

Definition at line 207 of file pci.c.

References pci_dev::bus, scan_bus(), and scan_device().

Referenced by scan_bus().

◆ scan_device()

void scan_device ( uint8_t bus,
uint8_t dev )
static

Prints the functions of a device, for debugging.

Definition at line 190 of file pci.c.

References pci_dev::bus, pci_dev::func, get_class_code(), get_device_id(), get_subclass_code(), get_vendor_id(), printk(), and scan_device().

Referenced by scan_bus(), and scan_device().

Variable Documentation

◆ host

struct pci_host* host
static

Definition at line 23 of file pci.c.

Referenced by pci_assign(), pci_host_set(), pci_irq(), pci_read_dword(), and pci_write_dword().

◆ pcidev

struct dev pcidev
Initial value:
= {
.probe = pci_prope,
}
int pci_prope()
The PCI module's initialization, which has nothing to do: drivers find their devices themselves.
Definition pci.c:220

Definition at line 225 of file pci.c.