[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1033679: hw-detect/check-missing-firmware: add fallback module lookup by modalias and firmware



Package: src:hw-detect
Version: 1.155
Tags: patch

Dear maintainer,
Please find attached 3 patches adding fallback module detection when dmesg does not provide the actual module name and device driver symlink is missing. I tried to keep them as clear, short and little invasive as possible in order to ease review and avoid regressions. Tested with p54usb (follow-up to bug #1032377). Tested for non regression with b43.

===============

* 0001 check-missing-firmware: add function get_module_by_bus_address

Call this function for bus types other than usb and mhi. It looks up:
- module name
- driver name
- sysfs modalias
- udevadm modalias
in order and returns whichever exists or matches first.

===============

* 0002 check-missing-firmware: call get_module_by_bus_address for usb devices too

So modalias lookup can be used with usb devices when no driver is found
(e.g. p54usb).

===============

* 0003 check-missing-firmware: add module lookup by firmware file

Scan all loaded modules for the requested firmware file as fallback if the detected module is a bus name or is not a loaded driver or module name.
From dba86861a56abfbca0f6c760262326ce2c511707 Mon Sep 17 00:00:00 2001
From: Pascal Hambourg <pascal@plouf.fr.eu.org>
Date: Thu, 30 Mar 2023 00:19:42 +0200
Subject: [PATCH 1/3] check-missing-firmware: add function
 get_module_by_bus_address

Call this function for bus types other than usb and mhi. It looks up:
- <device>/driver/module
- <device>/driver
- <device>/modalias
- udevadm <device> modalias
in order, and returns whichever exists or matches first.
---
 check-missing-firmware.sh | 45 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/check-missing-firmware.sh b/check-missing-firmware.sh
index 5db0e180..c5356f27 100755
--- a/check-missing-firmware.sh
+++ b/check-missing-firmware.sh
@@ -21,6 +21,44 @@ log_output() {
 	log-output -t check-missing-firmware "$@"
 }
 
+get_module_by_bus_address () {
+	local bus=$1
+	local address=$2
+	local device="/sys/bus/$bus/devices/$address"
+	local modalias=
+
+	# return associated module name if it exists
+	if [ -e "$device"/driver/module ]; then
+		basename $(readlink "$device"/driver/module)
+		return
+	fi
+	# else return associated driver name if it exists
+	log "no module found for $bus $address, looking up driver"
+	if [ -e "$device"/driver ]; then
+		basename $(readlink "$device"/driver)
+		return
+	fi
+	log "no driver found for $bus $address, looking up modalias"
+	# else lookup module by modalias if it exists
+	# warning: requires kmod, busybox modprobe does not support --resolve-alias
+	if [ -e "$device"/modalias ]; then
+		modalias="$(cat "$device"/modalias)"
+	else
+		# modalias may not exist in sysfs but only in udev, so also query udevadm
+		log "no modalias found for $bus $address in sysfs, looking up udevadm"
+		modalias="$(udevadm info --query=property $device | grep "^MODALIAS=" | sed 's/^MODALIAS=//')"
+	fi
+	if [ -n "$modalias" ]; then
+		modprobe --resolve-alias "$modalias" 2>/dev/null && return
+		log "no module matching modalias found for $bus $address"
+	else
+		log "no modalias found for $bus $address"
+	fi
+	log "failed to perform $bus $address lookup"
+	log "=> sticking with the $bus module"
+	echo "$bus"
+}
+
 # USB is special, and we don't want to take it all done:
 get_usb_module() {
 	address="$1"
@@ -166,6 +204,13 @@ check_missing () {
 		    module=$(get_mhi_holders)
 		    log "using $module instead of mhi"
 		;;
+		*)
+		    # other bus types
+		    if [ -e /sys/bus/"$module" ]; then
+			bus="$module"
+			module=$(get_module_by_bus_address "$bus" "$address")
+		    fi
+		;;
 	    esac
 
 	    # ignore specific files:
-- 
2.30.2

From b2b56617e9008a74c97d0576bb75a6e5857c800c Mon Sep 17 00:00:00 2001
From: Pascal Hambourg <pascal@plouf.fr.eu.org>
Date: Thu, 30 Mar 2023 00:36:01 +0200
Subject: [PATCH 2/3] check-missing-firmware: call get_module_by_bus_address
 for usb devices too

So modalias lookup can be tried with usb devices when no driver is found
(e.g. p54usb).
---
 check-missing-firmware.sh | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/check-missing-firmware.sh b/check-missing-firmware.sh
index c5356f27..2d2414d8 100755
--- a/check-missing-firmware.sh
+++ b/check-missing-firmware.sh
@@ -77,9 +77,7 @@ get_usb_module() {
 	# Make sure driver resolution returns something:
 	driver=$(basename $(readlink "$subdirs/driver") 2>/dev/null)
 	if [ "$driver" = "" ]; then
-		log "failed to perform usb $address lookup (no driver found)"
-		log "=> sticking with the usb module"
-		echo 'usb'
+		get_module_by_bus_address "usb" "$(basename $subdirs)"
 		return
 	fi
 	echo $driver
-- 
2.30.2

From e4b6a9061061c638d6169562dece6f151901353c Mon Sep 17 00:00:00 2001
From: Pascal Hambourg <pascal@plouf.fr.eu.org>
Date: Thu, 30 Mar 2023 00:51:37 +0200
Subject: [PATCH 3/3] check-missing-firmware: add module lookup by firmware
 file

Scan all loaded modules for the requested firmware file as fallback if the detected
module is a bus name or is not a loaded driver nor module name.
---
 check-missing-firmware.sh | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/check-missing-firmware.sh b/check-missing-firmware.sh
index 2d2414d8..0c71c243 100755
--- a/check-missing-firmware.sh
+++ b/check-missing-firmware.sh
@@ -59,6 +59,25 @@ get_module_by_bus_address () {
 	echo "$bus"
 }
 
+get_module_by_firmware () {
+	local firmware=$1
+	local module module_path holder
+
+	for module_path in /sys/module/* ; do
+		module="$(basename "$module_path")"
+		if /sbin/modinfo -F firmware "$module" 2>/dev/null | grep -q "^$firmware$" ; then
+			# if a module advertising firmware is used by another module, the latter must be reloaded too
+			# e.g. rtw88_*, atmel*, orinoco*, snd_vx*
+			for holder in $(find -L "$module_path"/holders/ -mindepth 1 -maxdepth 1 -exec basename {} ';') ; do
+				module="$module $holder"
+			done
+			echo "$module"
+			return
+		fi
+	done
+	log "no module matching firmware $firmware found"
+}
+
 # USB is special, and we don't want to take it all done:
 get_usb_module() {
 	address="$1"
@@ -211,6 +230,15 @@ check_missing () {
 		;;
 	    esac
 
+	    if [ -e /sys/bus/"$module" -o \
+		 \( ! -e /sys/module/"$module" -a -z "$(find /sys/bus/*/drivers -maxdepth 1 -name "$module")" \) ]; then
+		# $module is a bus name or not a module name nor a driver name, so look up by firmware
+		module_by_fw="$(get_module_by_firmware "$fwfile")"
+		if [ -n "$module_by_fw" ]; then
+			module="$module_by_fw"
+		fi
+	    fi
+
 	    # ignore specific files:
 	    #  - iwlwifi, debug-only (#969264, #966218)
 	    if [ "$fwfile" = "iwl-debug-yoyo.bin" ]; then
-- 
2.30.2


Reply to: