linux6.1 配置mcp2518fd驱动
说明
mcp2518fd适配,它是一个spi转can芯片。芯片勘误上说是spi速率最多10m,不然内部存储会有问题。
硬件
只用一个中断脚的硬件原理图配置:

三个中断脚都用的硬件原理图配置:

步骤
开启设备树和内核选项。
&spi0 {
status = "okay";
max-freq = <5000000>;
pinctrl-names = "default";
pinctrl-0 = <&spi0m0_csn0 &spi0m0_pins>;
mcp251xfd_0: mcp251xfd_0@0 {
status = "okay";
compatible = "microchip,mcp2518fd";
reg = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mcp251xfd>;
clocks = <&spi_clk_mcp251xfd_40M>;
spi-max-frequency = <5000000>; // 原来是 10000000
interrupts-extended = <&gpio0 RK_PD3 IRQ_TYPE_LEVEL_LOW>;
// 用RX中断脚的情况
// microchip,rx-int-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
vdd-supply = <&vcc_ext3v3_ext5v0>;
xceiver-supply = <&vcc_ext3v3_ext5v0>;
};
};
这样其实就可以了,但是为了在只用一个中断脚的情况下防止那两个中断脚有问题,可以直接配置为GPIO。
index 185202bad4cd..a1d4ff823fb3 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -592,8 +592,15 @@ static int mcp251xfd_chip_rx_int_enable(const struct mcp251xfd_priv *priv)
{
u32 val;
- if (!priv->rx_int)
- return 0;
+ if (!priv->rx_int) {
+ /* 未使用 RX-INT GPIO 时,也要把 PIN0/PIN1 配置为 GPIO 输入,
+ * 避免它们停留在复位默认的特殊功能模式(SOF/RXINT)。
+ * 否则 RX 中断可能被分流到 GPIO1,导致 nINT 收不到 RX 中断。
+ */
+ val = MCP251XFD_REG_IOCON_PM1 | MCP251XFD_REG_IOCON_PM0 |
+ MCP251XFD_REG_IOCON_TRIS1 | MCP251XFD_REG_IOCON_TRIS0;
+ return regmap_write(priv->map_reg, MCP251XFD_REG_IOCON, val);
+ }
/* Configure GPIOs:
* - PIN0: GPIO Input
(END)
解决spi转can的can不插连接线然后直接发送,内核中断报错的问题
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 1665f78abb5c..185202bad4cd 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -25,6 +25,10 @@
#define DEVICE_NAME "mcp251xfd"
+/* IRQ 错误恢复:连续恢复失败退避上限,超过后停止自动恢复,
+ * 防止 SPI 恢复风暴打满 CPU(见 mcp251xfd_irq 的 out_fail 路径) */
+#define MCP251XFD_RECOVER_RETRY_MAX 10
+
static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp2517fd = {
.quirks = MCP251XFD_QUIRK_MAB_NO_WARN | MCP251XFD_QUIRK_CRC_REG |
MCP251XFD_QUIRK_CRC_RX | MCP251XFD_QUIRK_CRC_TX |
@@ -1474,7 +1478,16 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
if (!(intf_pending)) {
can_rx_offload_threaded_irq_finish(&priv->offload);
- return handled;
+
+ /* 虚假中断:SPI 读正常但芯片没有待处理的中断
+ * (INT 引脚毛刺/电平噪声,常见于 SPI 传输期间)。
+ * 返回 IRQ_HANDLED,防止 spurious 计数累积导致
+ * "nobody cared" 禁用中断。真中断下次仍会触发。
+ */
+ dev_info_once(priv->ndev->dev.parent,
+ "spurious IRQ: no pending ints (intf=0x%08x).\n",
+ priv->regs_status.intf);
+ return IRQ_HANDLED;
}
/* Some interrupts must be ACKed in the
@@ -1582,10 +1595,47 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
err, priv->regs_status.intf);
mcp251xfd_dump(priv);
- mcp251xfd_chip_interrupts_disable(priv);
- mcp251xfd_timestamp_stop(priv);
- return handled;
+ /* SPI 通信失败时,芯片的中断标志可能无法清除,INT 引脚会一直
+ * 保持低电平,导致 GPIO 电平中断风暴;而每次都返回 IRQ_NONE
+ * 会让内核累积 spurious 计数,最终 "nobody cared" 禁用中断。
+ * 这里软复位芯片恢复 SPI 状态机,并返回 IRQ_HANDLED 保住中断。
+ *
+ * 连续失败超过上限后停止自动恢复(总线持续异常时避免 SPI
+ * 恢复风暴打满 CPU),仅保住中断不被禁用。
+ */
+ if (priv->recover_fail_cnt >= MCP251XFD_RECOVER_RETRY_MAX)
+ return IRQ_HANDLED;
+
+ err = mcp251xfd_chip_start(priv);
+ if (!err) {
+ int i;
+
+ /* chip_start() 已重置 TX/RX ring,旧的 echo skb 不再有
+ * 对应的 TEF 条目,必须全部释放,防止 skb 泄漏和
+ * can_get_echo_skb() 统计/释放错乱。
+ */
+ for (i = 0; i < priv->tx->obj_num; i++)
+ can_free_echo_skb(priv->ndev, i, NULL);
+
+ err = mcp251xfd_chip_interrupts_enable(priv);
+ }
+ if (err) {
+ priv->recover_fail_cnt++;
+ netdev_err(priv->ndev,
+ "Failed to recover chip after IRQ error (%d, cnt=%u).\n",
+ err, priv->recover_fail_cnt);
+
+ /* 恢复失败:停队列并上报上层状态,避免"假运行" */
+ can_change_state(priv->ndev, NULL, CAN_STATE_BUS_OFF,
+ CAN_STATE_BUS_OFF);
+ netif_stop_queue(priv->ndev);
+ } else {
+ priv->recover_fail_cnt = 0;
+ netif_wake_queue(priv->ndev);
+ }
+
+ return IRQ_HANDLED;
}
static int mcp251xfd_open(struct net_device *ndev)
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
index b98ded7098a5..376b088010da 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
@@ -659,6 +659,17 @@ struct mcp251xfd_priv {
struct mcp251xfd_devtype_data devtype_data;
struct can_berr_counter bec;
+
+ /* IRQ 错误恢复:连续失败计数(超过 MCP251XFD_RECOVER_RETRY_MAX
+ * 后停止自动恢复,防止恢复风暴)。
+ *
+ * 并发边界:恢复路径只在 mcp251xfd_irq(threaded)中执行,而
+ * mcp251xfd_open() 在 request_threaded_irq() 之前完成 chip_start,
+ * mcp251xfd_stop() 在 chip_stop() 之前 free_irq(),因此与
+ * open/stop 天然互斥。若将来启用 restart-ms(can_restart → do_set_mode
+ * → chip_start),需在此加锁串行化。
+ */
+ u8 recover_fail_cnt;
};
#define MCP251XFD_IS(_model) \
本文来自博客园,作者:杨旭0324,转载请注明原文链接:https://www.cnblogs.com/allalonewithyou/p/22630996,个人邮箱:yaonie4444@foxmail.com

浙公网安备 33010602011771号