[documentation][device_driver_model] Add comprehensive PIC documentation (EN) - critical module 1/6

Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-03 15:08:51 +00:00
parent c7dd64349a
commit b10da2d554

View File

@@ -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 <rtthread.h>
#include <rtdevice.h>
#include <drivers/pic.h>
#include <drivers/platform.h>
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 <rtthread.h>
#include <drivers/pic.h>
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: <hwirq trigger_type> */
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