Kernel

gpio gpiochip0核心錯誤是什麼意思以及如何解決?

  • March 27, 2022

我在我的日誌中發現了這個:

kernel: gpio gpiochip0: (gpio_aaeon): tried to insert a GPIO chip with zero lines
kernel: gpiochip_add_data_with_key: GPIOs 0..-1 (gpio_aaeon) failed to register, -22
kernel: gpio-aaeon: probe of gpio-aaeon.0 failed with error -22

這是什麼意思,我應該如何解決它?

lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 21.04
Release:        21.04
Codename:       hirsute

這些消息是由核心通用 I/O 程式碼產生的,顯然是在嘗試載入此更新檔或其更開發的等效模組引入的模組時。

精簡版:

模組找到它正在尋找的 WMI 程式介面,但忽略了介面報告硬體中沒有可控 GPIO 線的事實。它應該已停止註冊嘗試並拒絕模組安裝並顯示-ENODEV錯誤程式碼。您可以通過將gpio-aaeon模組列入黑名單來刪除消息,即通過創建一個名為 eg 的文件/etc/modprobe.d/no-aaeon-gpio-here.conf,其內容如下:

blacklist gpio-aaeon

您在該核心模組中發現了一個錯誤,並且可能希望將其報告給 Linux GPIO 開發人員。您的硬體似乎為測試gpio_aaeon模組提供了一個有趣的“角落案例”,開發人員顯然沒有考慮過。這是可以理解的,因為該模組似乎相當新:我上面連結的更新檔是在今年 5 月下旬發布的。


長版:

GPIO 子系統抱怨該gpio_aaeon模組試圖註冊一個實際上沒有任何通用 I/O 線來控制的晶片,因此將這樣的晶片註冊到 GPIO 子系統是沒有意義的。

註冊發生在模組的探測函式中:

+static int __init aaeon_gpio_probe(struct platform_device *pdev)
+{
+   int err, i;
+   int dio_number = 0;
+   struct aaeon_gpio_data *data;
+   struct aaeon_gpio_bank *bank;
+
+   /* Prevent other drivers adding this platfom device */
+   if (!wmi_has_guid(AAEON_WMI_MGMT_GUID)) {
+       pr_debug("AAEON Management GUID not found\n");
+       return -ENODEV;
+   }
+
+   dio_number = aaeon_gpio_get_number();
+   if (dio_number < 0)
+       return -ENODEV;
+
+   data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+   if (!data)
+       return -ENOMEM;
+
+   data->nr_bank = ARRAY_SIZE(aaeon_gpio_bank);
+   data->bank = aaeon_gpio_bank;
+   platform_set_drvdata(pdev, data);
+   bank = &data->bank[0];
+   bank->chip.parent = &pdev->dev;
+   bank->chip.ngpio = dio_number;
+   bank->data = data;
+   err = devm_gpiochip_add_data(&pdev->dev, &bank->chip, bank);
+   if (err)
+       pr_debug("Failed to register gpiochip %d: %d\n", i, err);
+
+   return err;
+}

由於載入模組的嘗試並沒有簡單地以-ENODEV錯誤結束,因此您的系統顯然具有此驅動程序正在尋找的 WMI 管理 API……但是當被查詢時,該 API 實際上表示它沒有什麼可控制的。

換句話說,模組可以繼續dio_number = aaeon_gpio_get_number();呼叫,最終只是呼叫一個 WMI 方法來獲取一個整數,這顯然是可通過此 API 控制的 GPIO 線數。WMI 方法沒有返回錯誤……但它報告的行數顯然是 0。

該函式繼續分配一些記憶體並開始建構 Linux GPIO 子系統所需的結構以註冊 GPIO 線以進行控制。完成後,它會呼叫devm_gpiochip_add_data()GPIO 子系統的函式來註冊一個新的 GPIO 晶片……但是 GPIO 子系統會執行一些完整性檢查,並註意到這些結構實際上指定了晶片中有 0 條 GPIO 線要控制。

根據Elixir.bootlin.com Linux kernel cross-referencer,這devm_gpiochip_add_data()是一個宏,它只呼叫devm_gpiochip_add_data_with_key()最後兩個參數為空的函式。這反過來又會呼叫gpiochip_add_data_with_key()函式,這將產生您在第 #628 行看到的第一條錯誤消息。

之後的其他消息隨著函式呼叫鏈的展開而產生,因為每個函式都向其呼叫者返回一個錯誤程式碼。

如果返回的值aaeon_gpio_get_number()確實是 WMI API 可以控制的 GPIO 線數,那麼測試:

+   if (dio_number < 0)
+       return -ENODEV;

實際上應該是:

+   if (dio_number < 1)
+       return -ENODEV;

但是如果 WMI API 返回的數字實際上意味著一些微妙的不同,比如“最後一個可控 GPIO 線的從 0 開始的數字”(即值 0 表示“只有一個 GPIO 線 #0,沒有其他”),然後將dio_number用作 的值會bank->chip.ngpio導致一個錯誤,並且模組將錯過所有具有此用於 GPIO 的 WMI API 的系統中的最後一個可控 GPIO 線。

因此,無論哪種方式,都需要解決一些問題。

引用自:https://unix.stackexchange.com/questions/665526