irq_set_affinity_hint设置irq的affinity

本文详细介绍了Linux系统中如何通过irq_set_affinity_hint函数来设置中断的CPU亲和性,包括函数内部调用流程及如何查看设置后的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在驱动中可以调用irq_set_affinity_hint来来设施cpu的affinity
int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m)
{
    unsigned long flags;
    struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);

    if (!desc)
        return -EINVAL;
    desc->affinity_hint = m;
    irq_put_desc_unlock(desc, flags);
    /* set the initial affinity to prevent every interrupt being on CPU0 */
如果struct cpumask *m不为0,就调用__irq_set_affinity 来设置affinity,如果为0的话,表示没有affinity,irq 可以运行到任何cpu上,之所以有m为0的case是因为调用request_irq 的时候irq 默认都是绑定到cpu0 上的,设置m为null,可以解除这个绑定
    if (m)
        __irq_set_affinity(irq, m, false);
    return 0;
}

int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force)
{
    struct irq_desc *desc = irq_to_desc(irq);
    unsigned long flags;
    int ret;

    if (!desc)
        return -EINVAL;

    raw_spin_lock_irqsave(&desc->lock, flags);
    ret = irq_set_affinity_locked(irq_desc_get_irq_data(desc), mask, force);
    raw_spin_unlock_irqrestore(&desc->lock, flags);
    return ret;
}
继续调用irq_set_affinity_locked
int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
                bool force)
{
    struct irq_chip *chip = irq_data_get_irq_chip(data);
    struct irq_desc *desc = irq_data_to_desc(data);
    int ret = 0;

    if (!chip || !chip->irq_set_affinity)
        return -EINVAL;

    if (irq_can_move_pcntxt(data)) {
        ret = irq_do_set_affinity(data, mask, force);
    } else {
        irqd_set_move_pending(data);
        irq_copy_pending(desc, mask);
    }

    if (desc->affinity_notify) {
        kref_get(&desc->affinity_notify->kref);
        schedule_work(&desc->affinity_notify->work);
    }
    irqd_set(data, IRQD_AFFINITY_SET);

    return ret;
}
假定irq_can_move_pcntxt 返回ture ,则继续调用irq_do_set_affinity
int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
            bool force)
{
    struct irq_desc *desc = irq_data_to_desc(data);
    struct irq_chip *chip = irq_data_get_irq_chip(data);
    int ret;

    ret = chip->irq_set_affinity(data, mask, force);
    switch (ret) {
    case IRQ_SET_MASK_OK:
    case IRQ_SET_MASK_OK_DONE:
        cpumask_copy(desc->irq_common_data.affinity, mask);
    case IRQ_SET_MASK_OK_NOCOPY:
        irq_set_thread_affinity(desc);
        ret = 0;
    }

    return ret;
}
最终即使设定desc->irq_common_data.affinity 这个变量
这样当你调用cat /proc
static int show_irq_affinity(int type, struct seq_file *m, void *v)
{
    struct irq_desc *desc = irq_to_desc((long)m->private);
    const struct cpumask *mask = desc->irq_common_data.affinity;

#ifdef CONFIG_GENERIC_PENDING_IRQ
    if (irqd_is_setaffinity_pending(&desc->irq_data))
        mask = desc->pending_mask;
#endif
    if (type)
        seq_printf(m, "%*pbl\n", cpumask_pr_args(mask));
    else
        seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
    return 0;
}

    /* create /proc/irq/<irq>/smp_affinity */
    proc_create_data("smp_affinity", 0644, desc->dir,
             &irq_affinity_proc_fops, (void *)(long)irq);

这样当你调用proc/irq/<irq>/smp_affinity的时候就可以看到这个irq的affinity
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 核心上。代码展示
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 核心上。
06-09
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值