Skip to content

Instantly share code, notes, and snippets.

@r15ch13
Last active July 23, 2024 00:52
Show Gist options
  • Save r15ch13/ba2d738985fce8990a4e9f32d07c6ada to your computer and use it in GitHub Desktop.
Save r15ch13/ba2d738985fce8990a4e9f32d07c6ada to your computer and use it in GitHub Desktop.
List IOMMU Groups and the connected USB Devices
#!/usr/bin/env bash
shopt -s nullglob
lastgroup=""
for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
for d in $g/devices/*; do
if [ "${g##*/}" != "$lastgroup" ]; then
echo -en "Group ${g##*/}:\t"
else
echo -en "\t\t"
fi
lastgroup=${g##*/}
lspci -nms ${d##*/} | awk -F'"' '{printf "[%s:%s]", $4, $6}'
if [[ -e "$d"/reset ]]; then echo -en " [R] "; else echo -en " "; fi
lspci -mms ${d##*/} | awk -F'"' '{printf "%s %-40s %s\n", $1, $2, $6}'
for u in ${d}/usb*/; do
bus=$(cat "${u}/busnum")
lsusb -s $bus: | \
awk '{gsub(/:/,"",$4); printf "%s|%s %s %s %s|", $6, $1, $2, $3, $4; for(i=7;i<=NF;i++){printf "%s ", $i}; printf "\n"}' | \
awk -F'|' '{printf "USB:\t\t[%s]\t\t %-40s %s\n", $1, $2, $3}'
done
done
done
@relaydenied
Copy link

Kik Azz!

@jtxnn678
Copy link

jtxnn678 commented Dec 15, 2023

Open source router N5105 output:

root@pve ~# ./iommu.sh
Group 0: [8086:4e61] [R] 00:02.0 VGA compatible controller JasperLake [UHD Graphics]
Group 1: [8086:4e24] 00:00.0 Host bridge Device 4e24
Group 2: [8086:4e03] 00:04.0 Signal processing controller Dynamic Tuning service
Group 3: [8086:4ded] 00:14.0 USB controller Device 4ded
USB: [046d:c52b] Bus 001 Device 002 Logitech, Inc. Unifying Receiver
USB: [1d6b:0002] Bus 001 Device 001 Linux Foundation 2.0 root hub
USB: [1d6b:0003] Bus 002 Device 001 Linux Foundation 3.0 root hub
[8086:4def] 00:14.2 RAM memory Device 4def
Group 4: [8086:4de0] 00:16.0 Communication controller Management Engine Interface
Group 5: [8086:4dd3] 00:17.0 SATA controller Device 4dd3
Group 6: [8086:4db8] [R] 00:1c.0 PCI bridge Device 4db8
Group 7: [8086:4dbc] [R] 00:1c.4 PCI bridge Device 4dbc
Group 8: [8086:4dbd] [R] 00:1c.5 PCI bridge Device 4dbd
Group 9: [8086:4dbe] [R] 00:1c.6 PCI bridge Device 4dbe
Group 10: [8086:4dbf] [R] 00:1c.7 PCI bridge Device 4dbf
Group 11: [8086:4d87] 00:1f.0 ISA bridge Device 4d87
[8086:4dc8] 00:1f.3 Audio device Jasper Lake HD Audio
[8086:4da3] 00:1f.4 SMBus Jasper Lake SMBus
[8086:4da4] 00:1f.5 Serial bus controller Jasper Lake SPI Controller
Group 12: [1cc1:8201] [R] 01:00.0 Non-Volatile memory controller XPG SX8200 Pro PCIe Gen3x4 M.2 2280 Solid State Drive
Group 13: [8086:125c] [R] 02:00.0 Ethernet controller Ethernet Controller I226-V
Group 14: [8086:125c] [R] 03:00.0 Ethernet controller Ethernet Controller I226-V
Group 15: [8086:125c] [R] 04:00.0 Ethernet controller Ethernet Controller I226-V
Group 16: [8086:125c] [R] 05:00.0 Ethernet controller Ethernet Controller I226-V

@anchaides
Copy link

Thank you!

@digitalformula
Copy link

Is there any way to expand this to show more details about the Ethernet controllers e.g. their MAC address? When passing raw devices through in Proxmox etc it is nearly impossible to correctly match IOMMU group to Ethernet controllers as it doesn't show which connected NICs relate to each IOMMU group.

@mitchty
Copy link

mitchty commented Jul 10, 2024

@digitalformula yeah something like this (quick hack):

iommu group 15:
02:00.0 Network controller [0280]: Intel Corporation Wi-Fi 6E(802.11ax) AX210/AX1675* 2x2 [Typhoon Peak] [8086:2725] (rev 1a)
net:    wlp2s0  mac ff:ff:ff:ff:ff:ff

I adapted this script a bit to be posix shell and only what I need, but this is what I abuse:

cur=''
for dir in $(find /sys/kernel/iommu_groups/ -type l | sort -n -k5 -t/); do
  iommu=${dir#*/iommu_groups/*}
  iommu=${iommu%%/*}
  if [ "${iommu}" != "${cur}" ]; then
    printf 'iommu group %s:\n' "${iommu}"
    cur="${iommu}"
  fi

  lspci -nns "${dir##*/}"

  for usb in ${dir}/usb*/; do
    if [ -e "${usb}/busnum" ]; then
      bus=$(cat "${usb}/busnum")
      lsusb -s "${bus}": \
        | awk '{gsub(/:/,"",$4); printf "%s|%s %s %s %s|", $6, $1, $2, $3, $4; for(i=7;i<=NF;i++){printf "%s ", $i}; printf "\n"}' \
        | awk -F'|' '{printf "usb:\t[%s]\t %-40s %s\n", $1, $2, $3}'
    fi
  done

  for net in ${dir}/net/*; do
    if [ -e "${net}/address" ]; then
      name=$(basename "${net}")
      mac=$(cat "${net}/address")
      printf "net:\t%s\tmac %s\n" "${name}" "${mac}"
    fi
  done
done

You could snag more stuff out of the device tree but device name/mac is a decent enough start.

@digitalformula
Copy link

@digitalformula yeah something like this (quick hack):

iommu group 15:
02:00.0 Network controller [0280]: Intel Corporation Wi-Fi 6E(802.11ax) AX210/AX1675* 2x2 [Typhoon Peak] [8086:2725] (rev 1a)
net:    wlp2s0  mac ff:ff:ff:ff:ff:ff

I adapted this script a bit to be posix shell and only what I need, but this is what I abuse:

cur=''
for dir in $(find /sys/kernel/iommu_groups/ -type l | sort -n -k5 -t/); do
  iommu=${dir#*/iommu_groups/*}
  iommu=${iommu%%/*}
  if [ "${iommu}" != "${cur}" ]; then
    printf 'iommu group %s:\n' "${iommu}"
    cur="${iommu}"
  fi

  lspci -nns "${dir##*/}"

  for usb in ${dir}/usb*/; do
    if [ -e "${usb}/busnum" ]; then
      bus=$(cat "${usb}/busnum")
      lsusb -s "${bus}": \
        | awk '{gsub(/:/,"",$4); printf "%s|%s %s %s %s|", $6, $1, $2, $3, $4; for(i=7;i<=NF;i++){printf "%s ", $i}; printf "\n"}' \
        | awk -F'|' '{printf "usb:\t[%s]\t %-40s %s\n", $1, $2, $3}'
    fi
  done

  for net in ${dir}/net/*; do
    if [ -e "${net}/address" ]; then
      name=$(basename "${net}")
      mac=$(cat "${net}/address")
      printf "net:\t%s\tmac %s\n" "${name}" "${mac}"
    fi
  done
done

You could snag more stuff out of the device tree but device name/mac is a decent enough start.

Brilliant, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment