From b10da2d55442f6d93eb099beb5deeabd206965d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 3 Jan 2026 15:08:51 +0000 Subject: [PATCH] [documentation][device_driver_model] Add comprehensive PIC documentation (EN) - critical module 1/6 Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com> --- .../device_driver_model/pic/README.md | 966 ++++++++++++++++++ 1 file changed, 966 insertions(+) create mode 100644 documentation/6.components/device-driver/device_driver_model/pic/README.md diff --git a/documentation/6.components/device-driver/device_driver_model/pic/README.md b/documentation/6.components/device-driver/device_driver_model/pic/README.md new file mode 100644 index 0000000000..1cc483f0f3 --- /dev/null +++ b/documentation/6.components/device-driver/device_driver_model/pic/README.md @@ -0,0 +1,966 @@ +# Platform Interrupt Controller (PIC) Framework + +## Introduction + +The Platform Interrupt Controller (PIC) framework provides a unified abstraction layer for managing hardware interrupts in RT-Thread's Device Driver Model. It supports various interrupt controllers including ARM GIC (Generic Interrupt Controller) v1/v2/v3, and provides comprehensive interrupt management capabilities including cascading, MSI support, and inter-processor interrupts (IPI). + +### Key Features + +- **Unified Interrupt Management**: Abstract interface for all interrupt controllers +- **Interrupt Cascading**: Support for hierarchical interrupt routing +- **CPU Affinity**: Configure which CPUs can handle specific interrupts +- **Priority Control**: Set interrupt priorities for different IRQ sources +- **Trigger Modes**: Support edge/level triggered interrupts +- **IPI Support**: Inter-processor interrupt mechanisms for multi-core systems +- **MSI/MSI-X**: Message Signaled Interrupts for PCIe devices +- **Statistics**: Optional ISR execution time tracking + +### Architecture + +The PIC framework consists of: + +1. **PIC Core** (`pic.c`): Central interrupt management and routing +2. **PIC IRQ** (`struct rt_pic_irq`): Individual interrupt descriptor +3. **PIC Operations** (`struct rt_pic_ops`): Hardware-specific callbacks +4. **ISR Management**: Interrupt Service Routine registration and execution + +``` +┌──────────────────────────────────────────┐ +│ Application/Drivers │ +│ (Call rt_pic_attach_irq, enable, etc.) │ +└──────────────────┬───────────────────────┘ + │ +┌──────────────────▼───────────────────────┐ +│ PIC Framework (pic.c) │ +│ - IRQ allocation & management │ +│ - ISR dispatch │ +│ - Cascading support │ +│ - Affinity & priority management │ +└──────────────────┬───────────────────────┘ + │ +┌──────────────────▼───────────────────────┐ +│ PIC Operations (rt_pic_ops) │ +│ - irq_enable/disable │ +│ - irq_mask/unmask │ +│ - irq_set_priority │ +│ - irq_set_affinity │ +│ - irq_send_ipi (for multi-core) │ +└──────────────────┬───────────────────────┘ + │ +┌──────────────────▼───────────────────────┐ +│ Hardware Interrupt Controller │ +│ (GICv2, GICv3, etc.) │ +└──────────────────────────────────────────┘ +``` + +## Kconfig Configuration + +### Location in menuconfig + +``` +RT-Thread Components + └── Device Drivers + └── Using Device Driver Model with DeviceTree (RT_USING_DM) + └── Using Programmable Interrupt Controller (PIC) (RT_USING_PIC) +``` + +### Configuration Options + +#### RT_USING_PIC +- **Type**: bool +- **Default**: n +- **Description**: Enable the Platform Interrupt Controller framework +- **Dependencies**: RT_USING_DM, RT_USING_ADT, RT_USING_ADT_BITMAP +- **Purpose**: Main switch for PIC support + +#### RT_USING_PIC_STATISTICS +- **Type**: bool +- **Default**: n +- **Description**: Enable ISR execution time statistics +- **Dependencies**: RT_USING_PIC, RT_USING_KTIME, RT_USING_INTERRUPT_INFO +- **Purpose**: Track min/max/average IRQ handling times for profiling + +#### MAX_HANDLERS +- **Type**: int +- **Range**: 1-4294967294 +- **Default**: 256 +- **Description**: Maximum number of interrupt handlers the system can register +- **Purpose**: Defines the size of the global IRQ hash table + +#### RT_PIC_ARM_GIC +- **Type**: bool +- **Default**: n +- **Description**: Enable ARM Generic Interrupt Controller v1/v2 support +- **Dependencies**: RT_USING_PIC, RT_USING_OFW +- **Purpose**: Support for ARM GICv1/v2 hardware + +#### RT_PIC_ARM_GIC_V2M +- **Type**: bool +- **Default**: n +- **Description**: Enable ARM GIC V2M (MSI support for GICv2) +- **Dependencies**: RT_PIC_ARM_GIC, RT_PCI_MSI, RT_USING_OFW +- **Purpose**: Message Signaled Interrupts on GICv2 + +#### RT_PIC_ARM_GIC_V3 +- **Type**: bool +- **Default**: n +- **Description**: Enable ARM Generic Interrupt Controller v3 support +- **Dependencies**: RT_USING_PIC, RT_USING_OFW +- **Purpose**: Support for ARM GICv3 hardware + +#### RT_PIC_ARM_GIC_V3_ITS +- **Type**: bool +- **Default**: n +- **Description**: Enable ARM GICv3 ITS (Interrupt Translation Service) +- **Dependencies**: RT_PIC_ARM_GIC_V3, RT_PCI_MSI, RT_USING_OFW, RT_USING_ADT_REF +- **Purpose**: MSI/MSI-X support for GICv3 via ITS + +#### RT_PIC_ARM_GIC_V3_ITS_IRQ_MAX +- **Type**: int +- **Default**: 127 (64-bit), 63 (32-bit) +- **Description**: Maximum IRQ number for GICv3 ITS +- **Dependencies**: RT_PIC_ARM_GIC_V3_ITS +- **Purpose**: Limit ITS-managed interrupt range + +## Device Tree Bindings + +### GICv2 Example + +```dts +gic: interrupt-controller@08000000 { + compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + interrupt-controller; + reg = <0x08000000 0x1000>, /* Distributor */ + <0x08010000 0x1000>; /* CPU interface */ +}; + +/* Consumer example: UART using GIC */ +uart0: serial@09000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x09000000 0x1000>; + interrupts = <0 5 4>; /* SPI, IRQ 5, IRQ_TYPE_LEVEL_HIGH */ + interrupt-parent = <&gic>; +}; +``` + +### GICv3 Example + +```dts +gic: interrupt-controller@08000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + interrupt-controller; + reg = <0x0 0x08000000 0 0x10000>, /* Distributor */ + <0x0 0x080A0000 0 0xF60000>; /* Redistributor */ + + gic_its: msi-controller@08020000 { + compatible = "arm,gic-v3-its"; + msi-controller; + #msi-cells = <1>; + reg = <0x0 0x08020000 0 0x20000>; + }; +}; + +/* Consumer with interrupts */ +timer { + compatible = "arm,armv8-timer"; + interrupts = <1 13 0xff08>, /* Physical Secure PPI */ + <1 14 0xff08>, /* Physical Non-Secure PPI */ + <1 11 0xff08>, /* Virtual PPI */ + <1 10 0xff08>; /* Hypervisor PPI */ + interrupt-parent = <&gic>; +}; +``` + +### Interrupt Cells Explanation + +For ARM GIC, `interrupts` property has 3 cells: +1. **Type**: 0 = SPI (Shared Peripheral Interrupt), 1 = PPI (Private Peripheral Interrupt) +2. **Number**: IRQ number within the type (SPI: 0-987, PPI: 0-15) +3. **Flags**: Trigger type and priority + - `IRQ_TYPE_EDGE_RISING` = 1 + - `IRQ_TYPE_EDGE_FALLING` = 2 + - `IRQ_TYPE_LEVEL_HIGH` = 4 + - `IRQ_TYPE_LEVEL_LOW` = 8 + +## Application API + +### IRQ Attachment + +#### rt_pic_attach_irq + +```c +rt_err_t rt_pic_attach_irq(int irq, rt_isr_handler_t handler, void *uid, + const char *name, int flags); +``` + +Attach an interrupt service routine to an IRQ. + +**Parameters:** +- `irq`: IRQ number to attach to +- `handler`: ISR function pointer `void (*handler)(int irq, void *param)` +- `uid`: User-defined parameter passed to the handler +- `name`: Descriptive name for the interrupt (for debugging) +- `flags`: Interrupt flags (currently unused, pass 0) + +**Returns:** +- `RT_EOK`: Success +- `-RT_EINVAL`: Invalid IRQ number +- `-RT_ENOMEM`: Out of memory + +**Example:** +```c +void uart_isr(int irq, void *param) +{ + struct uart_device *uart = (struct uart_device *)param; + /* Handle interrupt */ + rt_kprintf("UART interrupt occurred\n"); +} + +/* In driver probe function */ +static rt_err_t uart_probe(struct rt_platform_device *pdev) +{ + struct uart_device *uart; + int irq; + + /* Get IRQ from device tree */ + irq = rt_platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + /* Attach ISR */ + rt_err_t ret = rt_pic_attach_irq(irq, uart_isr, uart, "uart0", 0); + if (ret != RT_EOK) + return ret; + + /* Enable the interrupt */ + rt_pic_irq_enable(irq); + + return RT_EOK; +} +``` + +#### rt_pic_detach_irq + +```c +rt_err_t rt_pic_detach_irq(int irq, void *uid); +``` + +Detach an interrupt service routine from an IRQ. + +**Parameters:** +- `irq`: IRQ number +- `uid`: Must match the `uid` passed to `rt_pic_attach_irq` + +**Returns:** +- `RT_EOK`: Success +- `-RT_EINVAL`: Invalid IRQ or UID mismatch + +### IRQ Control + +#### rt_pic_irq_enable / rt_pic_irq_disable + +```c +void rt_pic_irq_enable(int irq); +void rt_pic_irq_disable(int irq); +``` + +Enable or disable an interrupt at the PIC level. + +**Parameters:** +- `irq`: IRQ number + +**Example:** +```c +/* Enable interrupt before starting operation */ +rt_pic_irq_enable(uart_irq); + +/* Disable during critical sections */ +rt_pic_irq_disable(uart_irq); +/* ... critical code ... */ +rt_pic_irq_enable(uart_irq); +``` + +#### rt_pic_irq_mask / rt_pic_irq_unmask + +```c +void rt_pic_irq_mask(int irq); +void rt_pic_irq_unmask(int irq); +``` + +Mask or unmask an interrupt (similar to enable/disable but may have different semantics on some hardware). + +**Parameters:** +- `irq`: IRQ number + +#### rt_pic_irq_ack + +```c +void rt_pic_irq_ack(int irq); +``` + +Acknowledge an interrupt (required for some edge-triggered interrupts). + +**Parameters:** +- `irq`: IRQ number + +#### rt_pic_irq_eoi + +```c +void rt_pic_irq_eoi(int irq); +``` + +Signal End-Of-Interrupt to the PIC. + +**Parameters:** +- `irq`: IRQ number + +### Priority Management + +#### rt_pic_irq_set_priority + +```c +rt_err_t rt_pic_irq_set_priority(int irq, rt_uint32_t priority); +``` + +Set the priority of an interrupt. + +**Parameters:** +- `irq`: IRQ number +- `priority`: Priority value (lower = higher priority typically) + +**Returns:** +- `RT_EOK`: Success +- `-RT_ENOSYS`: Not supported by hardware + +**Example:** +```c +/* Set high priority for critical timer interrupt */ +rt_pic_irq_set_priority(timer_irq, 0); + +/* Set lower priority for UART */ +rt_pic_irq_set_priority(uart_irq, 128); +``` + +#### rt_pic_irq_get_priority + +```c +rt_uint32_t rt_pic_irq_get_priority(int irq); +``` + +Get the current priority of an interrupt. + +**Parameters:** +- `irq`: IRQ number + +**Returns:** Current priority value + +### CPU Affinity (Multi-core) + +#### rt_pic_irq_set_affinity + +```c +rt_err_t rt_pic_irq_set_affinity(int irq, rt_bitmap_t *affinity); +``` + +Set which CPUs can handle a specific interrupt. + +**Parameters:** +- `irq`: IRQ number +- `affinity`: Bitmap of allowed CPUs + +**Returns:** +- `RT_EOK`: Success +- `-RT_ENOSYS`: Not supported + +**Example:** +```c +RT_IRQ_AFFINITY_DECLARE(cpumask); + +/* Route interrupt to CPU 0 and CPU 2 */ +rt_bitmap_clear(cpumask, RT_BITMAP_LEN(RT_CPUS_NR)); +RT_IRQ_AFFINITY_SET(cpumask, 0); +RT_IRQ_AFFINITY_SET(cpumask, 2); +rt_pic_irq_set_affinity(eth_irq, cpumask); +``` + +#### rt_pic_irq_get_affinity + +```c +rt_err_t rt_pic_irq_get_affinity(int irq, rt_bitmap_t *out_affinity); +``` + +Get the current CPU affinity for an interrupt. + +**Parameters:** +- `irq`: IRQ number +- `out_affinity`: Output bitmap + +**Returns:** +- `RT_EOK`: Success +- `-RT_EINVAL`: Invalid IRQ + +### Trigger Mode + +#### rt_pic_irq_set_triger_mode + +```c +rt_err_t rt_pic_irq_set_triger_mode(int irq, rt_uint32_t mode); +``` + +Set the trigger mode for an interrupt. + +**Parameters:** +- `irq`: IRQ number +- `mode`: Trigger mode + - `RT_IRQ_MODE_EDGE_RISING`: Rising edge + - `RT_IRQ_MODE_EDGE_FALLING`: Falling edge + - `RT_IRQ_MODE_EDGE_BOTH`: Both edges + - `RT_IRQ_MODE_LEVEL_HIGH`: High level + - `RT_IRQ_MODE_LEVEL_LOW`: Low level + +**Returns:** +- `RT_EOK`: Success +- `-RT_ENOSYS`: Not supported + +#### rt_pic_irq_get_triger_mode + +```c +rt_uint32_t rt_pic_irq_get_triger_mode(int irq); +``` + +Get the current trigger mode. + +**Parameters:** +- `irq`: IRQ number + +**Returns:** Current trigger mode + +### Inter-Processor Interrupts (IPI) + +#### rt_pic_irq_send_ipi + +```c +void rt_pic_irq_send_ipi(int irq, rt_bitmap_t *cpumask); +``` + +Send an inter-processor interrupt to specified CPUs. + +**Parameters:** +- `irq`: IPI number (typically in range 0-15) +- `cpumask`: Bitmap of target CPUs + +**Example:** +```c +RT_IRQ_AFFINITY_DECLARE(targets); + +/* Send IPI to CPU 1 */ +rt_bitmap_clear(targets, RT_BITMAP_LEN(RT_CPUS_NR)); +RT_IRQ_AFFINITY_SET(targets, 1); +rt_pic_irq_send_ipi(0, targets); /* IPI 0 */ +``` + +### State Management + +#### rt_pic_irq_set_state / rt_pic_irq_get_state + +```c +rt_err_t rt_pic_irq_set_state(int irq, int type, rt_bool_t state); +rt_err_t rt_pic_irq_get_state(int irq, int type, rt_bool_t *out_state); +``` + +Set or get interrupt state (pending, active, masked). + +**Parameters:** +- `irq`: IRQ number +- `type`: State type + - `RT_IRQ_STATE_PENDING`: Interrupt is pending + - `RT_IRQ_STATE_ACTIVE`: Interrupt is being serviced + - `RT_IRQ_STATE_MASKED`: Interrupt is masked +- `state` / `out_state`: State value + +**Returns:** +- `RT_EOK`: Success +- `-RT_ENOSYS`: Not supported + +## Complete Driver Example: GPIO Interrupt Handler + +```c +#include +#include +#include +#include + +struct gpio_int_device +{ + struct rt_device parent; + void *base; + int irq; + rt_uint32_t pin_mask; +}; + +/* GPIO interrupt service routine */ +static void gpio_isr(int irq, void *param) +{ + struct gpio_int_device *gpio = (struct gpio_int_device *)param; + rt_uint32_t status; + + /* Read interrupt status register */ + status = readl(gpio->base + GPIO_INT_STATUS); + + /* Clear interrupt */ + writel(status, gpio->base + GPIO_INT_CLEAR); + + /* Handle each pin */ + for (int i = 0; i < 32; i++) + { + if (status & (1 << i)) + { + rt_kprintf("GPIO pin %d triggered\n", i); + /* Notify application or trigger event */ + } + } + + /* Send EOI to PIC */ + rt_pic_irq_eoi(irq); +} + +static rt_err_t gpio_int_probe(struct rt_platform_device *pdev) +{ + struct gpio_int_device *gpio; + struct rt_device *dev = &pdev->parent; + int irq; + rt_err_t ret; + + gpio = rt_calloc(1, sizeof(*gpio)); + if (!gpio) + return -RT_ENOMEM; + + /* Map registers */ + gpio->base = rt_dm_dev_iomap(dev, 0); + if (!gpio->base) + { + ret = -RT_ERROR; + goto err_free; + } + + /* Get IRQ from device tree */ + irq = rt_platform_get_irq(pdev, 0); + if (irq < 0) + { + ret = irq; + goto err_iounmap; + } + gpio->irq = irq; + + /* Set interrupt trigger mode - rising edge */ + ret = rt_pic_irq_set_triger_mode(irq, RT_IRQ_MODE_EDGE_RISING); + if (ret != RT_EOK && ret != -RT_ENOSYS) + { + rt_kprintf("Failed to set trigger mode: %d\n", ret); + goto err_iounmap; + } + + /* Set interrupt priority (high priority) */ + ret = rt_pic_irq_set_priority(irq, 32); + if (ret != RT_EOK && ret != -RT_ENOSYS) + { + rt_kprintf("Failed to set priority: %d\n", ret); + } + + /* Attach interrupt handler */ + ret = rt_pic_attach_irq(irq, gpio_isr, gpio, "gpio-int", 0); + if (ret != RT_EOK) + { + rt_kprintf("Failed to attach IRQ: %d\n", ret); + goto err_iounmap; + } + + /* Configure GPIO pins for interrupt */ + writel(0xFFFFFFFF, gpio->base + GPIO_INT_ENABLE); /* Enable all pins */ + writel(0x00000000, gpio->base + GPIO_INT_MASK); /* Unmask all */ + + /* Enable interrupt at PIC level */ + rt_pic_irq_enable(irq); + + /* Store device data */ + rt_platform_set_drvdata(pdev, gpio); + + rt_kprintf("GPIO interrupt controller probed successfully (IRQ %d)\n", irq); + return RT_EOK; + +err_iounmap: + rt_dm_dev_iounmap(dev, gpio->base); +err_free: + rt_free(gpio); + return ret; +} + +static rt_err_t gpio_int_remove(struct rt_platform_device *pdev) +{ + struct gpio_int_device *gpio = rt_platform_get_drvdata(pdev); + + /* Disable interrupt */ + rt_pic_irq_disable(gpio->irq); + + /* Detach handler */ + rt_pic_detach_irq(gpio->irq, gpio); + + /* Disable GPIO interrupts */ + writel(0x00000000, gpio->base + GPIO_INT_ENABLE); + + /* Cleanup */ + rt_dm_dev_iounmap(&pdev->parent, gpio->base); + rt_free(gpio); + + return RT_EOK; +} + +static const struct rt_ofw_node_id gpio_int_ofw_ids[] = +{ + { .compatible = "myvendor,gpio-interrupt-controller" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver gpio_int_driver = +{ + .name = "gpio-int", + .ids = gpio_int_ofw_ids, + .probe = gpio_int_probe, + .remove = gpio_int_remove, +}; + +static int gpio_int_drv_register(void) +{ + rt_platform_driver_register(&gpio_int_driver); + return 0; +} +INIT_DEVICE_EXPORT(gpio_int_drv_register); +``` + +## PIC Provider Implementation + +For implementing a custom interrupt controller driver: + +```c +#include +#include + +struct my_pic_data +{ + void *base; + struct rt_pic pic; +}; + +static void my_pic_irq_enable(struct rt_pic_irq *pirq) +{ + struct rt_pic *pic = pirq->pic; + struct my_pic_data *priv = pic->priv_data; + + /* Enable interrupt in hardware */ + writel(1 << pirq->hwirq, priv->base + MY_PIC_ENABLE_REG); +} + +static void my_pic_irq_disable(struct rt_pic_irq *pirq) +{ + struct rt_pic *pic = pirq->pic; + struct my_pic_data *priv = pic->priv_data; + + /* Disable interrupt in hardware */ + writel(1 << pirq->hwirq, priv->base + MY_PIC_DISABLE_REG); +} + +static void my_pic_irq_ack(struct rt_pic_irq *pirq) +{ + struct rt_pic *pic = pirq->pic; + struct my_pic_data *priv = pic->priv_data; + + /* Acknowledge interrupt */ + writel(1 << pirq->hwirq, priv->base + MY_PIC_ACK_REG); +} + +static void my_pic_irq_eoi(struct rt_pic_irq *pirq) +{ + struct rt_pic *pic = pirq->pic; + struct my_pic_data *priv = pic->priv_data; + + /* Send EOI signal */ + writel(1 << pirq->hwirq, priv->base + MY_PIC_EOI_REG); +} + +static rt_err_t my_pic_irq_set_priority(struct rt_pic_irq *pirq, rt_uint32_t priority) +{ + struct rt_pic *pic = pirq->pic; + struct my_pic_data *priv = pic->priv_data; + + /* Set priority in hardware register */ + writel(priority, priv->base + MY_PIC_PRIORITY_REG(pirq->hwirq)); + + return RT_EOK; +} + +static int my_pic_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq; + + /* Allocate software IRQ number */ + irq = pic->irq_start + hwirq; + + /* Configure trigger mode in hardware */ + /* ... */ + + return irq; +} + +static rt_err_t my_pic_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *args, + struct rt_pic_irq *out_pirq) +{ + if (args->args_count != 2) + return -RT_EINVAL; + + /* Parse: */ + out_pirq->hwirq = args->args[0]; + out_pirq->mode = args->args[1]; + + return RT_EOK; +} + +static const struct rt_pic_ops my_pic_ops = +{ + .name = "my-pic", + .irq_enable = my_pic_irq_enable, + .irq_disable = my_pic_irq_disable, + .irq_ack = my_pic_irq_ack, + .irq_eoi = my_pic_irq_eoi, + .irq_set_priority = my_pic_irq_set_priority, + .irq_map = my_pic_irq_map, + .irq_parse = my_pic_irq_parse, +}; + +static rt_err_t my_pic_probe(struct rt_platform_device *pdev) +{ + struct my_pic_data *priv; + rt_err_t ret; + + priv = rt_calloc(1, sizeof(*priv)); + if (!priv) + return -RT_ENOMEM; + + /* Map registers */ + priv->base = rt_dm_dev_iomap(&pdev->parent, 0); + if (!priv->base) + { + ret = -RT_ERROR; + goto err_free; + } + + /* Initialize PIC structure */ + priv->pic.ops = &my_pic_ops; + priv->pic.priv_data = priv; + + /* Allocate IRQ range (32 interrupts) */ + ret = rt_pic_linear_irq(&priv->pic, 32); + if (ret != RT_EOK) + { + rt_kprintf("Failed to allocate IRQs\n"); + goto err_iounmap; + } + + /* Configure each IRQ */ + for (int i = 0; i < 32; i++) + { + rt_pic_config_irq(&priv->pic, i, i); /* Map 1:1 */ + } + + /* Call user extensions if needed */ + rt_pic_user_extends(&priv->pic); + + /* Initialize hardware */ + writel(0xFFFFFFFF, priv->base + MY_PIC_DISABLE_REG); /* Disable all */ + writel(0xFFFFFFFF, priv->base + MY_PIC_CLEAR_REG); /* Clear pending */ + + rt_platform_set_drvdata(pdev, priv); + rt_kprintf("My PIC initialized with %d IRQs\n", 32); + + return RT_EOK; + +err_iounmap: + rt_dm_dev_iounmap(&pdev->parent, priv->base); +err_free: + rt_free(priv); + return ret; +} + +static const struct rt_ofw_node_id my_pic_ofw_ids[] = +{ + { .compatible = "myvendor,my-pic" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver my_pic_driver = +{ + .name = "my-pic", + .ids = my_pic_ofw_ids, + .probe = my_pic_probe, +}; + +RT_PIC_OFW_DECLARE(my_pic, my_pic_ofw_ids, my_pic_probe); +``` + +## Best Practices + +### For Interrupt Consumers + +1. **Always disable interrupts during cleanup**: + ```c + rt_pic_irq_disable(irq); + rt_pic_detach_irq(irq, uid); + ``` + +2. **Handle spurious interrupts**: + ```c + static void my_isr(int irq, void *param) + { + if (!check_interrupt_source()) + return; /* Spurious interrupt */ + + /* Handle interrupt */ + } + ``` + +3. **Use EOI for level-triggered interrupts**: + ```c + static void my_isr(int irq, void *param) + { + handle_interrupt(); + clear_interrupt_source(); /* Clear in device first */ + rt_pic_irq_eoi(irq); /* Then send EOI to PIC */ + } + ``` + +4. **Set appropriate priorities**: + - Critical real-time interrupts: 0-31 (highest) + - Normal device interrupts: 32-127 + - Low-priority interrupts: 128-255 + +5. **Consider CPU affinity on multi-core systems**: + ```c + /* Pin network interrupt to CPU 0 for better cache locality */ + RT_IRQ_AFFINITY_DECLARE(mask); + rt_bitmap_clear(mask, RT_BITMAP_LEN(RT_CPUS_NR)); + RT_IRQ_AFFINITY_SET(mask, 0); + rt_pic_irq_set_affinity(net_irq, mask); + ``` + +### For PIC Providers + +1. **Implement minimum required operations**: + - `irq_enable`, `irq_disable` + - `irq_ack` or `irq_eoi` + - `irq_map`, `irq_parse` + +2. **Use `rt_pic_linear_irq` for simple IRQ allocation**: + ```c + ret = rt_pic_linear_irq(pic, num_irqs); + ``` + +3. **Support cascading for hierarchical interrupt controllers**: + ```c + struct rt_pic_irq *parent_pirq = rt_pic_find_pirq(parent_pic, parent_irq); + rt_pic_cascade(child_pirq, parent_irq); + ``` + +4. **Implement statistics support** (optional): + ```c + #ifdef RT_USING_PIC_STATISTICS + /* Framework tracks this automatically */ + #endif + ``` + +## Troubleshooting + +### Interrupt Not Firing + +1. **Check interrupt is enabled**: + ```c + rt_pic_irq_enable(irq); + ``` + +2. **Verify device interrupt is not masked**: + - Check device-specific interrupt enable registers + - Ensure interrupt source is configured correctly + +3. **Confirm device tree configuration**: + - Verify `interrupts` property + - Check `interrupt-parent` is correct + +4. **Check trigger mode**: + - Edge vs. level triggered + - Active high vs. active low + +### Interrupt Storms + +1. **Always acknowledge/clear interrupts**: + ```c + /* Clear source BEFORE EOI */ + clear_device_interrupt(); + rt_pic_irq_eoi(irq); + ``` + +2. **For level-triggered, clear condition**: + - Level-triggered interrupts re-assert if condition persists + - Must clear the underlying condition in the device + +### ISR Not Called + +1. **Verify IRQ number**: + ```c + rt_kprintf("Attached to IRQ %d\n", irq); + ``` + +2. **Check MAX_HANDLERS**: + - Ensure IRQ < MAX_HANDLERS + +3. **Confirm attachment succeeded**: + ```c + ret = rt_pic_attach_irq(irq, isr, param, "name", 0); + if (ret != RT_EOK) + rt_kprintf("Attach failed: %d\n", ret); + ``` + +### Priority/Affinity Not Working + +- Some PICs don't support priority or affinity +- Check return value for `-RT_ENOSYS` +- Verify hardware capabilities + +## Performance Considerations + +1. **Keep ISRs short**: Defer heavy processing to threads +2. **Minimize register access**: Cache PIC state when possible +3. **Use shared interrupts carefully**: Check device status first +4. **Consider IRQ coalescing**: For high-rate interrupt sources +5. **Profile with statistics**: + ```c + /* Enable RT_USING_PIC_STATISTICS */ + /* Check /proc or debug output for timing data */ + ``` + +## Related Modules + +- **OFW (Device Tree)**: IRQ parsing and `interrupt-parent` resolution +- **Platform Device**: `rt_platform_get_irq` for IRQ retrieval +- **PCI**: MSI/MSI-X interrupt support via PIC +- **Pinctrl**: GPIO interrupt configuration + +## References + +- ARM GIC Architecture Specification +- Device Tree Interrupt Mapping Specification +- RT-Thread Interrupt Management Documentation +- `components/drivers/pic/pic.c` - Core implementation +- `components/drivers/include/drivers/pic.h` - API header