# 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