【问题标题】:Mapping device tree interrupt flags to devm_request_irq将设备树中断标志映射到 devm_request_irq
【发布时间】:2016-10-13 03:25:49
【问题描述】:

我目前正在为 Linux 编写用于 PowerPC 的设备驱动程序。

设备树入口如下:

// PPS Interrupt client 
pps_hwirq {
    compatible = "pps-hwirq";
    interrupts = <17 0x02>;                     // IPIC 17 = IRQ1, 0x02 = falling edge
    interrupt-parent = < &ipic >;
};

0x02 标志非常重要 - PPS 与下降沿对齐,但这在 GPS 接收器上并不通用,因此应该是可配置的。

在驱动的probe()函数中,获取IRQ号很简单:

hwirq = irq_of_parse_and_map(np, 0);
if (hwirq == NO_IRQ) {
    dev_err(&pdev->dev, "No interrupt found in the device tree\n");
    return -EINVAL;
}

但是如何将设备树中的 IRQ 标志映射到驱动程序呢?

/* ****TODO****: Get the interrupt flags from the device tree 
 * For now, hard code to suit my problem, but since this differs
 * by GPS receiver, it should be configurable.
 */
flags = IRQF_TRIGGER_FALLING;

/* register IRQ interrupt handler */
ret = devm_request_irq(&pdev->dev, data->irq, pps_hwint_irq_handler,
                       flags, data->info.name, data);

不幸的是,树中几乎没有(如果有的话)实际执行此工作的示例 - 大多数将此标志保留为 0(保持原样) - 这是当 grep 为 @987654327 时的结果的 sn-p @,注意标志的值:

./drivers/crypto/mxs-dcp.c:     ret = devm_request_irq(dev, dcp_vmi_irq, mxs_dcp_irq, 0,
./drivers/crypto/mxs-dcp.c:     ret = devm_request_irq(dev, dcp_irq, mxs_dcp_irq, 0,
./drivers/crypto/omap-sham.c:   err = devm_request_irq(dev, dd->irq, dd->pdata->intr_hdlr,
./drivers/crypto/omap-aes.c:            err = devm_request_irq(dev, irq, omap_aes_irq, 0,
./drivers/crypto/picoxcell_crypto.c:    if (devm_request_irq(&pdev->dev, irq->start, spacc_spacc_irq, 0,

或将其硬编码为硬件实际断言的内容:

./drivers/crypto/tegra-aes.c:   err = devm_request_irq(dev, dd->irq, aes_irq, IRQF_TRIGGER_HIGH |

那么如何将设备树中的这个属性与实际的驱动程序清晰地关联起来呢?

【问题讨论】:

  • 您要编写的驱动程序类型是什么?也就是说,你注册驱动的函数是什么?
  • 驱动程序的实际类型与问题无关 - 我让它使用硬编码为 IRQF_TRIGGER_FALLING 的标志,这基本上是其他驱动程序所做的(或将其设置为零以保持不变) .我想要做的是从设备树中填充这个值并给它devm_request_irq。

标签: linux-kernel linux-device-driver device-tree


【解决方案1】:

接下来我将展示在一些常见情况下如何从设备树中获取 IRQ 编号和 IRQ 标志:

  • 在 I2C 驱动程序中
  • 在平台驱动程序中
  • 手动

在 I2C 驱动程序中

总之

如果您正在编写 I2C 驱动程序,则无需手动从 DT 读取 IRQ 参数。您可以依靠 I2C 内核为您填充 IRQ 参数:

  • 在您的 probe() 函数中,client-&gt;irq 将包含 IRQ 号
  • devm_request_irq() 将自动使用来自 DT 的 IRQ 标志(只是不要将任何 IRQ 触发标志传递给该函数)。

详情

让我们看看i2c_device_probe() 函数(它是您的驱动程序的probe() 函数被调用的地方):

static int i2c_device_probe(struct device *dev)
{
    ...
    if (dev->of_node) {
        ...
        irq = of_irq_get(dev->of_node, 0);
    }
    ...
    client->irq = irq;
    ...
    status = driver->probe(client, i2c_match_id(driver->id_table, client));
}

所以,client-&gt;irq 将在您的驱动程序的探测函数中包含 IRQ 号。

至于 IRQ 标志:of_irq_get()(在上面的代码中)最终会调用 irqd_set_trigger_type(),它在内部为您的中断号存储 IRQ 标志(从设备树中读取)。所以,当你调用devm_request_irq() 时,它最终会以__setup_irq() 结束,然后它会继续:

/*
 * If the trigger type is not specified by the caller,
 * then use the default for this interrupt.
 */
if (!(new->flags & IRQF_TRIGGER_MASK))
    new->flags |= irqd_get_trigger_type(&desc->irq_data);

地点:

  • new-&gt;flags 包含您提供给 devm_request_irq() 的标志
  • irqd_get_trigger_type() 返回从 DT 获得的标志

换句话说,如果您不将 IRQ 标志传递给 devm_request_irq()(例如传递 0),它将使用从设备树获得的 IRQ 标志。

详情请参阅this question

在平台驱动程序中

您可以使用platform_get_irq() 获取IRQ 号。它还(内部)存储从 DT 获得的 IRQ 标志,因此如果您将 flags=0 传递给 devm_request_irq(),则将使用来自 DT 的标志。

手动

如果您的驱动程序不依赖内核框架,您必须手动获取 IRQ 值:

  • IRQ 号可以通过irq_of_parse_and_map() 获得(如您所述);此函数不仅返回 IRQ 编号,还存储您的 IRQ 编号的 IRQ 标志(最终通过调用irqd_set_trigger_type());存储的 IRQ 标志将在 devm_request_irq() 中自动使用,如果您不将 IRQ 触发器类型传递给它(例如,您可以传递 flags=0

  • IRQ flags可以通过irq_get_trigger_type()获得,但必须在执行irq_of_parse_and_map()之后才能获得

    所以您可能只需要运行irq_of_parse_and_map() 并让devm_request_irq() 为您处理标志(只要确保您没有将触发标志传递给它)。

【讨论】:

  • 你知道为什么如果我对 SPI 设备使用 request_irq() 或 devm_request_irq() (其中 spi_drv_probe 的作用与 i2c_device_probe 几乎相同),然后在卸载模块之后当然是执行 free_irq 或甚至显式调用 devm_free_irq,然后尝试再次加载相同的模块,我收到“irq: type mismatch, failed to map hwirq ...”消息?
  • @AlexanderAmelkin 我的猜测是其他一些设备与该 IRQ 冲突(可能是某些驱动程序中的一些错误),或者您的 free_irq() 没有被调用(或没有成功完成)。也许需要一些调试来找出根本原因。您可以从here 应用补丁并粘贴内核日志中的相应输出吗?顺便说一句,我想最好在 SO 上创建一个新问题,因为它似乎超出了这里的范围。
  • 感谢补丁链接。我肯定会进行调试,并且可能会自己发布一个新问题/答案。我只是认为这可能是一些我不知道的已知问题,或者我可能做错了什么。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-30
  • 2015-07-21
  • 2014-08-04
  • 1970-01-01
  • 2022-01-04
相关资源
最近更新 更多