Martin L Roth has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/87202?usp=email )
Change subject: Documentation: Add Device Operations ......................................................................
Documentation: Add Device Operations
Change-Id: I3ed78f8ce50bb3914f55b2cbb7f5eb668706949a Signed-off-by: Martin Roth gaumless@gmail.com --- A Documentation/internals/device_operations.md M Documentation/internals/index.md 2 files changed, 697 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/02/87202/1
diff --git a/Documentation/internals/device_operations.md b/Documentation/internals/device_operations.md new file mode 100644 index 0000000..c0c98d0 --- /dev/null +++ b/Documentation/internals/device_operations.md @@ -0,0 +1,696 @@ +# Device Operations in coreboot Firmware + +## Introduction + +The `device_operations` structure is a cornerstone of coreboot's +hardware abstraction layer. It represents a set of function pointers +defining how the firmware interacts with a specific hardware device +during various boot stages. This structure lets the coreboot +architecture establish a consistent interface for device initialization, +configuration, resource allocation, and ACPI table generation, while +allowing device-specific implementations behind this common interface. + +At its core, `device_operations` applies the strategy pattern in +systems programming. It decouples algorithms (device operations) from +the core boot sequence, allowing devices to define their own behavior +while the boot process follows a predictable flow. This pattern enables +coreboot to support a wide range of hardware platforms with minimal +changes to the core boot sequence code. + + +## Structure Definition + +The `device_operations` structure, defined in +`src/include/device/device.h`, consists of several function pointers, +each representing a specific operation performed on a device during +boot: + +```c +struct device_operations { + void (*read_resources)(struct device *dev); + void (*set_resources)(struct device *dev); + void (*enable_resources)(struct device *dev); + void (*init)(struct device *dev); + void (*final)(struct device *dev); + void (*scan_bus)(struct device *bus); + void (*enable)(struct device *dev); + void (*vga_disable)(struct device *dev); + void (*reset_bus)(struct bus *bus); + + int (*get_smbios_data)(struct device *dev, int *handle, + unsigned long *current); + void (*get_smbios_strings)(struct device *dev, struct smbios_type11 *t); + + unsigned long (*write_acpi_tables)(const struct device *dev, + unsigned long start, struct acpi_rsdp *rsdp); + void (*acpi_fill_ssdt)(const struct device *dev); + const char *(*acpi_name)(const struct device *dev); + const char *(*acpi_hid)(const struct device *dev); + + const struct pci_operations *ops_pci; + const struct i2c_bus_operations *ops_i2c_bus; + const struct spi_bus_operations *ops_spi_bus; + const struct smbus_bus_operations *ops_smbus_bus; + const struct pnp_mode_ops *ops_pnp_mode; + const struct gpio_operations *ops_gpio; + const struct mdio_bus_operations *ops_mdio; +}; +``` + + +### Core Resource Management Functions + +* `read_resources`: Discovers and collects resources required by the + device (I/O ports, memory regions, IRQs, etc.). This typically + involves reading configuration registers or static device tree + information. +* `set_resources`: Assigns finalized resources to the device after the + resource allocation phase. This writes the assigned base addresses, + lengths, and other parameters back to the device structure, but not + necessarily to hardware registers yet. +* `enable_resources`: Activates the assigned resources in the device's + hardware registers (e.g., writing to PCI BARs, enabling memory + decoding). + + +### Device Lifecycle Functions + +* `init`: Performs device-specific initialization, often requiring + access to the device's assigned resources. This is called after + resources have been enabled. +* `final`: Executes final setup or cleanup operations before the + payload is loaded. This is useful for tasks that depend on other + devices being initialized. +* `enable`: Enables the device in the hardware, often setting bits in + configuration registers to make the device active. Called after + `enable_resources`. + + +### Bus Management Functions + +* `scan_bus`: Enumerates child devices on a bus device (e.g., scanning + a PCI bus for devices, probing I2C devices). Only applicable to + devices that act as buses. +* `reset_bus`: Resets all devices on a specific bus. +* `vga_disable`: Disables VGA decoding on a PCI device when another VGA + device is active. Used to manage legacy VGA resources. + + +### System Table Generation Functions + +* `get_smbios_data`: Provides SMBIOS data specific to the device for + Type 9 (System Slots) or Type 41 (Onboard Devices Extended + Information). +* `get_smbios_strings`: Supplies string information for SMBIOS tables, + often related to the data provided by `get_smbios_data`. +* `write_acpi_tables`: Generates device-specific ACPI tables (like SSDTs) + or contributes data to system-wide tables. +* `acpi_fill_ssdt`: Adds device-specific objects (scopes, methods, data) + to the Secondary System Description Table (SSDT). +* `acpi_name`: Returns the ACPI name for the device (e.g., + `_SB.PCI0.GFX0`). This defines the device's path in the ACPI + namespace. +* `acpi_hid`: Returns the ACPI Hardware ID (HID) for the device (e.g., + `PNP0A08`). Used by the OS to match drivers. + + +### Bus-Specific Operation Pointers + +These fields point to bus-specific operation structures when a device +functions as a bus controller (or exposes bus-like functionality). See +the "Bus-Specific Operations" section for details. + +* `ops_pci`: Operations for PCI configuration space access. +* `ops_i2c_bus`: Operations for I2C bus transactions (read, write, + transfer). +* `ops_spi_bus`: Operations for SPI bus transactions. +* `ops_smbus_bus`: Operations for SMBus transactions. +* `ops_pnp_mode`: Operations for Plug-and-Play device configuration. +* `ops_gpio`: Operations for GPIO control (get, set, configure + direction/pulls). +* `ops_mdio`: Operations for MDIO (Management Data Input/Output) bus + access, used for Ethernet PHYs. + + +## Device Lifecycle in coreboot + +The function pointers in `device_operations` are called at specific +stages during the boot process, following a sequence defined in +coreboot's boot state machine (`src/lib/hardwaremain.c`). Understanding +this lifecycle helps developers implement appropriate behavior for each +function pointer. + + +### Boot Sequence and Device Operations + +coreboot's main device initialization sequence involves these boot +states: + +1. **BS_DEV_INIT_CHIPS** (`dev_initialize_chips()`): Initializes chip + drivers (`chip_operations`). +2. **BS_DEV_ENUMERATE** (`dev_enumerate()`): Discovers and enumerates + devices. + * Calls `scan_bus()` for each bus to detect child devices. +3. **BS_DEV_RESOURCES** (`dev_configure()`): Allocates resources across + all enumerated devices. + * Calls `read_resources()` for each device to discover required + resources. + * Calls `set_resources()` for each device to assign allocated + resources back to the `struct device`. +4. **BS_DEV_ENABLE** (`dev_enable()`): Enables devices and their + resources. + * Calls `enable_resources()` for each device to activate assigned + resources in hardware. + * Calls `enable()` for each device to perform general hardware + enablement. +5. **BS_DEV_INIT** (`dev_initialize()`): Initializes devices. + * Calls `init()` for each device to perform device-specific setup. +6. **BS_POST_DEVICE** (`dev_finalize()`): Finalizes devices before + payload loading. + * Calls `final()` for each device for any final cleanup or setup. + +The sequence is primarily driven by the `boot_states` array in +`src/lib/hardwaremain.c`: + +```c +static struct boot_state boot_states[] = { + /* ... other states ... */ + BS_INIT_ENTRY(BS_PRE_DEVICE, bs_pre_device), + BS_INIT_ENTRY(BS_DEV_INIT_CHIPS, bs_dev_init_chips), + BS_INIT_ENTRY(BS_DEV_ENUMERATE, bs_dev_enumerate), + BS_INIT_ENTRY(BS_DEV_RESOURCES, bs_dev_resources), + BS_INIT_ENTRY(BS_DEV_ENABLE, bs_dev_enable), + BS_INIT_ENTRY(BS_DEV_INIT, bs_dev_init), + BS_INIT_ENTRY(BS_POST_DEVICE, bs_post_device), + /* ... other states ... */ +}; +``` + +Later stages include ACPI and SMBIOS table generation, where functions +like `write_acpi_tables()`, `acpi_fill_ssdt()`, `get_smbios_data()`, and +`get_smbios_strings()` are invoked as part of the table construction +process. + + +## Inheritance and Code Reuse Patterns + +The `device_operations` structure enables several patterns for code +reuse: + + +### 1. Default Implementations + +coreboot provides default implementations for common device types (like +root devices, PCI devices, PCI bridges), which can be used directly or +extended. Chip or mainboard code often assigns these defaults if no +specific driver is found. + +```c +/* From src/device/root_device.c */ +struct device_operations default_dev_ops_root = { + .read_resources = noop_read_resources, + .set_resources = noop_set_resources, + .scan_bus = scan_static_bus, + .reset_bus = root_dev_reset, +#if CONFIG(HAVE_ACPI_TABLES) + .acpi_name = root_dev_acpi_name, +#endif +}; +``` + + +### 2. No-op Functions + +Simple shim functions (often static inline) are provided for cases where +a device doesn't need to implement specific operations. Using these avoids +leaving function pointers NULL. + +```c +/* From src/include/device/device.h */ +static inline void noop_read_resources(struct device *dev) {} +static inline void noop_set_resources(struct device *dev) {} +``` + + +### 3. Chain of Responsibility / Delegation + +Some implementations delegate to parent devices or use helper functions +when they can't handle an operation themselves or when common logic can +be shared. For example, ACPI name generation often traverses up the +device tree. + +```c +/* Simplified example logic */ +const char *acpi_device_name(const struct device *dev) +{ + const char *name = NULL; + const struct device *pdev = dev; + + /* Check for device specific handler */ + if (dev->ops && dev->ops->acpi_name) { + name = dev->ops->acpi_name(dev); + if (name) + return name; /* Device handled it */ + } + + /* Walk up the tree to find if any parent can provide a name */ + while (pdev->upstream && pdev->upstream->dev) { + pdev = pdev->upstream->dev; + if (pdev->ops && pdev->ops->acpi_name) { + /* Note: Parent's acpi_name might handle the original child 'dev' */ + name = pdev->ops->acpi_name(dev); + if (name) + return name; /* Parent handled it */ + } + } + + /* Fallback or default logic if needed */ + return NULL; +} +``` +This pattern allows parent devices (like buses) to provide default +behavior or naming schemes if a child device doesn't specify its own. + + +## Implementation Examples + +These examples show typical `device_operations` assignments. Actual +implementations might involve more conditional compilation based on +Kconfig options. + + +### PCI Device Operations (Default) + +```c +/* From src/device/pci_device.c */ +struct device_operations default_pci_ops_dev = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, +#if CONFIG(HAVE_ACPI_TABLES) + .write_acpi_tables = pci_rom_write_acpi_tables, + .acpi_fill_ssdt = pci_rom_ssdt, +#endif + .init = pci_dev_init, + /* Assigns PCI-specific operations */ + .ops_pci = &pci_dev_ops_pci, +}; +``` + + +### CPU Cluster Operations + +```c +/* From src/soc/intel/alderlake/chip.c (representative example) */ +static struct device_operations cpu_bus_ops = { + .read_resources = noop_read_resources, + .set_resources = noop_set_resources, + .enable_resources = cpu_set_north_irqs, +#if CONFIG(HAVE_ACPI_TABLES) + .acpi_fill_ssdt = cpu_fill_ssdt, +#endif + /* CPU clusters often don't need scan_bus, init, etc. */ +}; +``` + + +### GPIO Controller Operations + +```c +/* From src/soc/intel/common/block/gpio/gpio_dev.c */ +static struct gpio_operations gpio_ops = { + .get = gpio_get, + .set = gpio_set, + /* ... other GPIO functions ... */ +}; + +struct device_operations block_gpio_ops = { + .read_resources = noop_read_resources, + .set_resources = noop_set_resources, + /* Assigns GPIO-specific operations */ + .ops_gpio = &gpio_ops, +}; +``` + + +## Registration and Discovery + +How are `device_operations` structures associated with `struct device` +instances? + + +### 1. Static Assignment (via `chip_operations`) + +For devices known at build time (defined in devicetree.cb), the +`device_operations` structure is often assigned in the SOC's or +mainboard's `chip_operations->enable_dev()` function based on the +device path type or other properties. + +```c +/* Example from src/soc/intel/alderlake/chip.c */ +static void soc_enable(struct device *dev) +{ + /* Assign ops based on the device's role in the tree */ + if (dev->path.type == DEVICE_PATH_DOMAIN) + dev->ops = &pci_domain_ops; /* Handles PCI domain resources */ + else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) + dev->ops = &cpu_bus_ops; /* Handles CPU cluster setup */ + else if (dev->path.type == DEVICE_PATH_GPIO) + block_gpio_enable(dev); /* Assigns block_gpio_ops */ + /* ... other assignments for specific PCI devices, etc. ... */ +} +``` +The `enable_dev` function is part of `struct chip_operations`, which +handles broader chip-level initialization (see "Relationship with +`chip_operations`" section). + + +### 2. Dynamic Detection (PCI Drivers) + +For PCI devices discovered during bus scanning (`scan_bus`), coreboot +looks through a list of registered PCI drivers (`_pci_drivers` array) +to find one matching the device's vendor and device IDs. + +```c +/* Logic from src/device/pci_device.c::set_pci_ops() */ +static void set_pci_ops(struct device *dev) +{ + struct pci_driver *driver; + + /* Check if ops already assigned (e.g., by chip_ops->enable_dev) */ + if (dev->ops) + return; + + /* Look through registered PCI drivers */ + for (driver = &_pci_drivers[0]; driver != &_epci_drivers[0]; driver++) { + if ((driver->vendor == dev->vendor) && + device_id_match(driver, dev->device)) { + /* Found a matching driver, assign its ops */ + dev->ops = (struct device_operations *)driver->ops; + printk(BIOS_SPEW, "%s: Assigned ops from driver for %04x:%04x\n", + dev_path(dev), driver->vendor, driver->device); + return; /* Stop searching */ + } + } + + /* Fall back to default operations if no specific driver found */ + if (!dev->ops) { + if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + dev->ops = get_pci_bridge_ops(dev); /* Special ops for bridges */ + } else { + dev->ops = &default_pci_ops_dev; /* Default for normal devices */ + } + printk(BIOS_SPEW, "%s: Assigned default PCI ops\n", dev_path(dev)); + } +} +``` + + +## Build Process Integration + +The `device_operations` structures are integrated into the coreboot +build process: + +1. **Static Device Tree**: The mainboard's `devicetree.cb` defines the + initial device hierarchy. The build process converts this into C + code (`static.c`) containing `struct device` instances. +2. **PCI Driver Registration**: PCI drivers (containing their own + `device_operations`) register themselves using the `__pci_driver` + linker set macro. + + ```c + /* Example pattern */ + struct pci_driver example_pci_driver __pci_driver = { + .ops = &example_device_ops, /* Pointer to device_operations */ + .vendor = VENDOR_ID, + .device = DEVICE_ID, /* Or .devices for a list */ + }; + ``` +3. **Linking**: The build system collects all structures placed in the + `__pci_driver` section and creates the `_pci_drivers` array used by + `set_pci_ops()`. It ensures all necessary code (default ops, driver + ops, core device functions) is linked into the final firmware image. + + +## Relationship with `chip_operations` + +It's important to distinguish `device_operations` from +`chip_operations` (defined in `src/include/chip.h`). + +* `chip_operations`: Defines operations related to the overall chipset + or mainboard logic. It includes functions called earlier in the boot + process, like `enable_dev`, `init`, and `final`. + * `chip_operations->enable_dev()` is crucial as it often performs + initial setup for static devices and is the primary place where + `device_operations` pointers are *assigned* for non-PCI devices + based on their path or type. + * `chip_operations->init()` runs during `BS_DEV_INIT_CHIPS`, before + most `device_operations` functions. +* `device_operations`: Defines operations for *individual* devices + within the device tree. These are called *after* the corresponding + `chip_operations` stage and operate on a specific `struct device`. + +Essentially, `chip_operations` sets the stage at the SoC/mainboard level, +including assigning the correct `device_operations` to static devices, +while `device_operations` handles the specific actions for each device +later in the boot process. + + +## Bus-Specific Operations + +The `ops_*` pointers within `struct device_operations` (e.g., `ops_pci`, +`ops_i2c_bus`, `ops_spi_bus`, `ops_gpio`) provide a way for devices that +act as bus controllers or expose bus-like interfaces to offer +standardized access methods. + +* **Purpose:** They abstract the low-level details of interacting with + that specific bus type. For example, a PCI host bridge device will + implement `struct pci_operations` via its `ops_pci` pointer, + allowing other code to perform PCI config reads/writes through it + without knowing the exact hardware mechanism. Similarly, an I2C + controller device implements `struct i2c_bus_operations` via + `ops_i2c_bus` to provide standard `read`, `write`, and `transfer` + functions for that bus segment. +* **Usage:** Code needing to interact with a bus first finds the + controller `struct device` in the tree, then accesses the relevant + bus operations through the appropriate `ops_*` pointer, passing the + target address or parameters. For instance, to talk to an I2C device + at address `0x50` on the bus controlled by `i2c_controller_dev`, one + might call: + `i2c_controller_dev->ops->ops_i2c_bus->transfer(...)`. Helper + functions often wrap this access pattern. +* **Implementation:** The structures like `struct pci_operations`, + `struct i2c_bus_operations`, etc., are defined in corresponding + header files (e.g., `src/include/device/pci_ops.h`, + `src/include/drivers/i2c/i2c_bus.h`). Devices acting as controllers + provide concrete implementations of these functions, tailored to their + hardware. + +This mechanism allows coreboot to manage diverse bus types using a +consistent device model, where the controller device itself exposes the +necessary functions for interacting with devices on its bus. + + +## Best Practices + +When implementing `device_operations`: + +1. **Leverage Defaults/No-ops**: Use default or no-op implementations + whenever possible. Only override functions that require custom + behavior for your specific device. +2. **Error Handling**: Check return values from functions called within + your ops implementations and handle errors gracefully (e.g., log an + error, return an error code if applicable). +3. **Resource Management**: In `read_resources`, accurately declare all + resources (MMIO, I/O ports, IRQs) your device needs, specifying + flags like fixed vs. alignment, or bridge vs. standard device. + Incorrect resource declaration is a common source of issues. +4. **Initialization Order**: Be mindful of dependencies in `init`. If + your device relies on another device being fully initialized, consider + deferring that part of the initialization to the `final` callback, + which runs later. +5. **Minimal Implementation**: Only implement the functions relevant to + your device type. A simple MMIO device might only need + `read_resources`, `set_resources`, `enable_resources`, and perhaps + ACPI functions. A bus device additionally needs `scan_bus`. +6. **Bus Operations**: If implementing a bus controller, correctly + implement the corresponding bus operations structure (e.g., + `struct pci_operations`, `struct i2c_bus_operations`) and assign it + to the appropriate `ops_*` field. +7. **ACPI/SMBIOS**: If the device needs OS visibility via ACPI or + SMBIOS, implement the relevant functions (`acpi_name`, `acpi_hid`, + `acpi_fill_ssdt`, `get_smbios_data`, etc.). Ensure ACPI names and + HIDs are correct according to specifications and platform needs. + + +## Logging and Debugging + +Use coreboot's logging facilities (`printk`) within your `device_operations` +functions to provide visibility during development and debugging. Use +appropriate log levels (e.g., `BIOS_DEBUG`, `BIOS_INFO`, `BIOS_ERR`). + +```c +static void example_device_init(struct device *dev) +{ + printk(BIOS_DEBUG, "%s: Initializing device at %s\n", __func__, + dev_path(dev)); + + /* ... Device initialization code ... */ + if (/* some condition */) { + printk(BIOS_SPEW, "%s: Condition met, applying setting X\n", + dev_path(dev)); + /* ... */ + } + + if (/* error condition */) { + printk(BIOS_ERR, "%s: Failed to initialize feature Y!\n", + dev_path(dev)); + /* Handle error */ + } + + printk(BIOS_DEBUG, "%s: Initialization complete for %s\n", __func__, + dev_path(dev)); +} +``` +Consistent logging helps trace the boot process and pinpoint where issues +occur. + + +## Common Troubleshooting + +* **Missing Resource Declarations**: + * *Problem*: Device fails to function, or conflicts arise because a + required resource (MMIO range, I/O port, IRQ) was not declared + in `read_resources`. The resource allocator is unaware of the + need. + * *Solution*: Verify that `read_resources` correctly calls functions + like `pci_dev_read_resources` or manually adds all necessary + resources using functions like `mmio_resource()`, + `io_resource()`, etc. Check PCI BARs or device datasheets. +* **Initialization Order Issues**: + * *Problem*: `init()` fails because it depends on another device + that hasn't been fully initialized yet (e.g., accessing a shared + resource like SMBus before the SMBus controller is ready). + * *Solution*: Move the dependent initialization code to the `final` + callback if possible. Alternatively, ensure the dependency is met + by careful ordering in the device tree or using boot state + callbacks if necessary for complex scenarios. +* **Resource Conflicts**: + * *Problem*: Boot fails during resource allocation, or devices + misbehave because multiple devices requested the same + non-sharable resource (e.g., conflicting fixed MMIO regions). + * *Solution*: Review resource declarations in `read_resources` across + all relevant devices. Ensure fixed resources don't overlap. Check + if bridge windows are correctly defined and large enough. Use + coreboot's resource reporting logs to identify overlaps. +* **ACPI Table Generation Errors**: + * *Problem*: The operating system fails to recognize the device, + assigns the wrong driver, or the device doesn't function correctly + (e.g., power management issues). + * *Solution*: Double-check the `acpi_name`, `acpi_hid`, `_CRS` + (generated from assigned resources), and `acpi_fill_ssdt` + implementations. Verify names match the ACPI hierarchy and HIDs + match expected driver bindings. Ensure SSDT methods correctly + access hardware. Use OS debugging tools (e.g., `acpidump`, Device + Manager errors) to diagnose. +* **Incorrect `ops` Pointer Assigned**: + * *Problem*: Device behaves incorrectly because the wrong + `device_operations` structure was assigned (e.g., default PCI ops + assigned to a device needing a specific driver's ops). + * *Solution*: Check the logic in `chip_operations->enable_dev` (for + static devices) or the PCI driver registration (`__pci_driver` + macro and `set_pci_ops` fallback logic) to ensure the correct + `ops` structure is being selected and assigned based on device + type, path, or PCI ID. Add debug prints to verify which `ops` + structure is assigned. + + +## Advanced Usage + +### Complex Device Hierarchies + +For devices with non-standard interactions or complex initialization, +custom `device_operations` can be created, often inheriting from defaults +but overriding specific functions. + +```c +static void advanced_device_init(struct device *dev) +{ + /* First, perform standard PCI init */ + pci_dev_init(dev); + + /* Then, add custom initialization steps */ + printk(BIOS_DEBUG, "%s: Performing advanced init\n", dev_path(dev)); + /* ... custom register writes, configuration ... */ +} + +static const char *advanced_device_acpi_name(const struct device *dev) +{ + /* Provide a custom ACPI name based on some property */ + if (/* condition */) + return "ADV0001"; + else + return "ADV0002"; +} + +/* Combine default and custom operations */ +static struct device_operations advanced_device_ops = { + /* Inherit resource handling from default PCI ops */ + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + + /* Override init */ + .init = advanced_device_init, + + /* Override ACPI naming */ + .acpi_name = advanced_device_acpi_name, + /* Other functions might use defaults or no-ops */ +}; +``` + +### Dynamic Configuration based on Probing + +Some `init` or other op implementations might probe the device's +capabilities or read configuration data (e.g., from SPD, VPD, or straps) +and alter their behavior accordingly. + +```c +static void conditional_device_init(struct device *dev) +{ + uint8_t feature_flags; + + /* Read capability register from the device */ + feature_flags = pci_read_config8(dev, EXAMPLE_CAP_REG); + + printk(BIOS_DEBUG, "%s: Feature flags: 0x%02x\n", dev_path(dev), + feature_flags); + + /* Conditional initialization based on detected features */ + if (feature_flags & FEATURE_X_ENABLED) { + printk(BIOS_INFO, "%s: Initializing Feature X\n", dev_path(dev)); + init_feature_x(dev); + } + if (feature_flags & FEATURE_Y_ENABLED) { + printk(BIOS_INFO, "%s: Initializing Feature Y\n", dev_path(dev)); + init_feature_y(dev); + } +} +``` + + +## Conclusion + +The `device_operations` structure is a powerful abstraction mechanism in +coreboot. It enables consistent handling of diverse hardware while +allowing for device-specific behavior. By providing a standard interface +for device operations throughout the boot process, it simplifies the +codebase, enhances maintainability, and provides the extensibility needed +to support new hardware platforms. + +Understanding this structure, its relationship with `chip_operations`, +and its role in the boot process is essential for coreboot developers, +particularly when adding support for new devices or debugging hardware +initialization issues. By following the patterns and best practices +outlined here, developers can create robust and reusable device driver +implementations that integrate smoothly into the coreboot architecture. diff --git a/Documentation/internals/index.md b/Documentation/internals/index.md index 9e55965..56c8221 100644 --- a/Documentation/internals/index.md +++ b/Documentation/internals/index.md @@ -11,4 +11,5 @@ coreboot devicetree <devicetree.md> coreboot devicetree language <devicetree_language.md> Chip Operations <chip_operations.md> +Device Operations <device_operations> ```