Linux内核与ARM:__irq_svc处理详解

需积分: 1 1 下载量 171 浏览量 更新于2024-08-23 收藏 635KB PPT 举报
"Linux系统驱动概述,__irq_svc处理过程,ARM架构,Linux内核目录结构,内核编程习惯,Linux内核的C语言特性" 在Linux系统驱动领域,理解内核工作原理至关重要,特别是对于异常处理和中断服务例程。在标题提到的`__irq_svc`处理过程中,这是ARM架构下中断服务例程(ISR)的特定部分。当一个中断发生时,处理器会跳转到`__irq_svc`这个特殊的系统服务子例程,进行中断处理。在这个过程中,堆栈从高地址向低地址增长,保存现场,即保存寄存器R0到R12的状态,以及LR(链接寄存器)、SPSR(中断服务程序状态寄存器)等关键信息,确保在中断处理结束后能正确恢复执行。 Linux系统驱动在ARM架构上的应用非常广泛,随着Linux内核的不断发展,它已经成功地在数百种不同的ARM处理器上运行。在Linux 2.4.x版本的内核目录结构中,可以看到`arch`目录下的`arm`子目录,这是专门为ARM架构定制的代码存放处。同时,还有如`drivers`、`fs`、`include`等核心组件,它们分别对应设备驱动、文件系统和头文件等。 阅读和理解Linux内核源码是一项挑战,因为其规模庞大,包含数百万行代码。内核编程习惯与应用程序编程有所不同,更强调效率和实时性。Linux内核主要使用扩展了ANSI C的GNU C,这意味着所有内核代码都必须通过GCC编译。GCC版本与内核的更新同步,例如,Linux 2.6内核推荐使用3.3及以上版本的GCC,以支持C99编程风格。 在编写内核代码时,开发者需要遵循特定的编程规范,比如使用静态类型检查、避免全局变量,以及充分利用内核提供的数据结构和API。此外,为了确保代码的可读性和可维护性,内核源码通常包含详细的注释和文档,这在`/Documentation`目录下可见。理解这些规范和实践对于开发高效、可靠的Linux系统驱动至关重要。

static void nvme_calc_irq_sets(struct irq_affinity *affd, unsigned int nrirqs) { struct nvme_dev *dev = affd->priv; unsigned int nr_read_queues, nr_write_queues = dev->nr_write_queues; if (!nrirqs) { nrirqs = 1; nr_read_queues = 0; } else if (nrirqs == 1 || !nr_write_queues) { nr_read_queues = 0; } else if (nr_write_queues >= nrirqs) { nr_read_queues = 1; } else { nr_read_queues = nrirqs - nr_write_queues; } dev->io_queues[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; affd->set_size[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; dev->io_queues[HCTX_TYPE_READ] = nr_read_queues; affd->set_size[HCTX_TYPE_READ] = nr_read_queues; affd->nr_sets = nr_read_queues ? 2 : 1; }static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) { struct pci_dev *pdev = to_pci_dev(dev->dev); struct irq_affinity affd = { //ָ���ж��׺��Եļ��㷽���Ͳ��� .pre_vectors = 1, .calc_sets = nvme_set_irq_affinity, //nvme_calc_irq_sets, .priv = dev, }; unsigned int irq_queues, poll_queues; poll_queues = min(dev->nr_poll_queues, nr_io_queues - 1); dev->io_queues[HCTX_TYPE_POLL] = poll_queues; dev->io_queues[HCTX_TYPE_DEFAULT] = 1; dev->io_queues[HCTX_TYPE_READ] = 0; irq_queues = 1; if (!(dev->ctrl.quirks & NVME_QUIRK_SINGLE_VECTOR)) irq_queues += (nr_io_queues - poll_queues); return pci_alloc_irq_vectors_affinity(pdev, 1, irq_queues, PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd); } 在 Linux 5.17.12 内核版本中,可以通过修改 pci_alloc_irq_vectors_affinity() 函数的 affinity_hint 参数来绑定 NVMe 驱动的所有 I/O 队列到同一 CPU 核心上。

2023-06-09 上传

static void nvme_calc_irq_sets(struct irq_affinity *affd, unsigned int nrirqs) { struct nvme_dev *dev = affd->priv; unsigned int nr_read_queues, nr_write_queues = dev->nr_write_queues; if (!nrirqs) { nrirqs = 1; nr_read_queues = 0; } else if (nrirqs == 1 || !nr_write_queues) { nr_read_queues = 0; } else if (nr_write_queues >= nrirqs) { nr_read_queues = 1; } else { nr_read_queues = nrirqs - nr_write_queues; } dev->io_queues[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; affd->set_size[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; dev->io_queues[HCTX_TYPE_READ] = nr_read_queues; affd->set_size[HCTX_TYPE_READ] = nr_read_queues; affd->nr_sets = nr_read_queues ? 2 : 1; }static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) { struct pci_dev *pdev = to_pci_dev(dev->dev); struct irq_affinity affd = { //ָ���ж��׺��Եļ��㷽���Ͳ��� .pre_vectors = 1, .calc_sets = nvme_set_irq_affinity, //nvme_calc_irq_sets, .priv = dev, }; unsigned int irq_queues, poll_queues; poll_queues = min(dev->nr_poll_queues, nr_io_queues - 1); dev->io_queues[HCTX_TYPE_POLL] = poll_queues; dev->io_queues[HCTX_TYPE_DEFAULT] = 1; dev->io_queues[HCTX_TYPE_READ] = 0; irq_queues = 1; if (!(dev->ctrl.quirks & NVME_QUIRK_SINGLE_VECTOR)) irq_queues += (nr_io_queues - poll_queues); return pci_alloc_irq_vectors_affinity(pdev, 1, irq_queues, PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd); } 在 Linux 5.17.12 内核版本中,如何修改 pci_alloc_irq_vectors_affinity() 函数的 affinity_hint 参数来绑定 NVMe 驱动的所有 I/O 队列到同一 CPU 核心上。代码展示

2023-06-09 上传