1#!/bin/sh 2#- 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2024 The FreeBSD Foundation 6# 7# This software was developed by Björn Zeeb 8# under sponsorship from the FreeBSD Foundation. 9# 10# This is neither efficient nor elegant but we need it few times 11# a year and it does the job. 12# 13# 14# USAGE: please check out the correct tag/hash for ports in the 15# linux-firmware.git repository you point this script to. 16# 17 18set -e 19 20DRIVER=ath11k 21CHECKFILE=debugfs_htt_stats.c 22 23################################################################################ 24# 25# Check pre-reqs 26# 27if [ $# -ne 1 ]; then 28 printf "USAGE: %s /path/to/linux-firmware.git\n" $0 >&2 29 exit 1 30fi 31 32if [ ! -e ${CHECKFILE} ]; then 33 printf "ERROR: run from %s driver directory; no %s.c here\n" ${DRIVER} ${CHECKFILE} >&2 34 exit 1 35fi 36 37LFWDIR=${1} 38if test ! -d ${LFWDIR} -o ! -e ${LFWDIR}/WHENCE; then 39 printf "ERROR: cannot find linux-firmware.git at '%s'\n" ${LFWDIR} >&2 40 exit 1 41fi 42LFWDIR=${LFWDIR}/${DRIVER} 43 44################################################################################ 45# 46# Helper functions. 47# 48# This uses a hack (cpp) to expand some macros for us and parses out the result 49# which is the PCI device ID or the firmware directory for that. 50# 51# Driver is there, the firmware not yet...? 52# ==> 0x1101 -> ATH11K_HW_QCA6390_HW20 -> QCA6390/hw2.0 53# ==> 0x1104 -> ATH11K_HW_QCN9074_HW10 -> QCN9074/hw1.0 54# ==> 0x1103 -> ATH11K_HW_WCN6855_HW20 -> WCN6855/hw2.0 55# ==> 0x1103 -> ATH11K_HW_WCN6855_HW21 -> WCN6855/hw2.1 56# Firmware dir WCN6855/hw2.1 (for 0x1103) does not exist; skipping 57# 58list_fw() 59{ 60 # List of already seen flavor (firmware directory). 61 sfwl="" 62 63 # List of "supported" device IDs. 64 devidl=$(cpp pci.c 2> /dev/null | awk '/PCI_VDEVICE\(QCOM,/ { gsub("^.*, ", ""); gsub("\\) },$", ""); print tolower($0); }') 65 # Turn them into a regex. 66 didreg=$(echo "${devidl}" | xargs -J % echo -n % | sed -e 's, ,|,g') 67 # List the device ID cases along with their hw_rev which we can go and take to lookup fw. 68 hwrevs=$(cpp pci.c 2> /dev/null | egrep -E "(case (${didreg})|ab->hw_rev = )" | awk '{ 69 if (FNR > 1 && /case/) { 70 printf "\n"; 71 } 72 gsub("^.*case[[:space:]]*", ""); 73 gsub("[[:space:]]*ab->hw_rev = ", " "); 74 gsub("[:;]", ""); 75 printf "%s", $0; 76 }') 77 78 # hwrevs is a list of (device IDs) -> (1..n hardware revisions) mappings. 79 #echo "==> ${devidl} :: ${didreg} :: ${hwrevs}" >&2 80 81 # List of (hardware revision) -> (firware directory) mappings. 82 l=$(cpp core.c 2> /dev/null | egrep -E '\.(hw_rev|dir) = ' | awk '{ if (/hw_rev/) { printf "%s", $0; } else { print; } }' | sort | uniq | \ 83 awk '{ 84 gsub("^.*hw_rev = ", ""); 85 gsub(",.* = ", "\t"); 86 gsub(",$", ""); 87 gsub(/"/, ""); 88 gsub(" ", ""); 89 gsub("\t", " "); 90 print; 91 }') 92 #echo "===> ${l}" >&2 93 94 ll=$(echo "${l}" | wc -w | awk '{ print $1 }') 95 while test "${ll}" -gt 1; do 96 hwr=${l%%[[:space:]]*} 97 l=${l#*[[:space:]]} 98 fwd=${l%%[[:space:]]*} 99 l=${l#*[[:space:]]} 100 101 #echo "=+=> ${hwr} -> ${fwd}" >&2 102 eval fwd_${hwr}=${fwd} 103 ll=$(echo "${l}" | wc -w | awk '{ print $1 }') 104 done 105 106 echo "${hwrevs}" | \ 107 while read did hwrl; do 108 hwrn=$(echo "${hwrl}" | wc -w | awk '{ print $1 }') 109 if test ${hwrn} -lt 1; then 110 printf "Device ID %s has no hardware revisions (%s); skipping\n" "${did}" ${hwrn} >&2 111 continue 112 fi 113 114 for hwrx in ${hwrl}; do 115 116 eval fwd=\${fwd_${hwrx}} 117 #echo "===> ${did} -> ${hwrx} -> ${fwd}" >&2 118 119 if test ! -d ${LFWDIR}/${fwd}; then 120 #printf "Firmware dir %s (for %s) does not exist; skipping\n" ${fwd} ${did} >&2 121 continue 122 fi 123 124 flav=$(echo "${fwd}" | awk -v drv=${DRIVER} '{ 125 # Ports FLAVOR names are [a-z0-9_]. If needed add more mangling magic here. 126 gsub("^" drv "/", ""); 127 gsub("/", "_"); 128 gsub("\\.", ""); 129 print tolower($0); 130 }') 131 132 # Print this first or otherwise if two device IDs have the same firmware 133 # we may not see that. 134 echo "FWGET ${did} ${flav}" 135 136 x="" 137 for zf in ${sfwl}; do 138 if test "${zf}" == "${flav}"; then 139 x="${zf}" 140 break 141 fi 142 done 143 if test "${x}" != ""; then 144 #printf "Flavor %s (firmware directory %s) already seen; skipping\n" ${flav} ${fwd} >&2 145 continue 146 fi 147 sfwl="${sfwl} ${flav}" 148 149 #echo "==> ${did} -> ${fwd} -> ${flav}" 150 151 lx=$(cd ${LFWDIR} && find ${fwd} -type f \! -name "*sdio*" -a \! -name "*.txt" -print) 152 153 # Get a count so we can automatically add \\ apart from the last line. 154 fn=$(echo "${lx}" | wc -w | awk '{ print $1 }') 155 156 #echo "==> ${flav} :: ${fn} :: ${lx}" >&2 157 158 if test ${fn} -gt 0; then 159 160 echo "FWS ${flav}" 161 echo "DISTFILES_${flav}= \\" 162 for fz in ${lx}; do echo "${fz}"; done | \ 163 awk -v fn=$fn -v fwg=${flav} -v drv=${DRIVER} '{ 164 if (FNR == fn) { x="" } else { x=" \\" }; 165 #gsub("^" drv "/", "${FWSUBDIR}/"); 166 gsub("^", "${FWSUBDIR}/"); 167 printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x; 168 }' 169 170 # Check for "lic" files. 171 lx=$(cd ${LFWDIR} && find ${fwd} -type f \! -name "*sdio*" -a -name "*.txt" -print) 172 173 # Get a count so we can automatically add \\ apart from the last line. 174 fn=$(echo "${lx}" | wc -w | awk '{ print $1 }') 175 176 if test ${fn} -gt 0; then 177 echo "FWL ${flav}" 178 echo "DISTFILES_${flav}_lic= \\" 179 for fz in ${lx}; do echo "${fz}"; done | \ 180 awk -v fn=$fn -v fwg=${flav} -v drv=${DRIVER} '{ 181 if (FNR == fn) { x="" } else { x=" \\" }; 182 #gsub("^" drv "/", "${FWSUBDIR}/"); 183 gsub("^", "${FWSUBDIR}/"); 184 printf "\t%s${DISTURL_SUFFIX}%s\n", $0, x; 185 }' 186 fi 187 fi 188 done 189 190 done 191} 192 193################################################################################ 194# 195# Generate the PORTS file template. 196# 197 198fwsl=$(list_fw | grep ^FWS | awk '{ print $2 }') 199# Get a count so we can automatically add \\ apart from the last line. 200fn=$(echo "${fwsl}" | wc -w | awk '{ print $1 }') 201 202if test ${fn} -gt 0; then 203 204 portsfile=$(mktemp -p /tmp ${DRIVER}-fwport.XXXXXX) 205 206 :> ${portsfile} 207 ( 208 echo "FWSUBS= \\" 209 for sz in ${fwsl}; do echo "${sz}"; done | \ 210 awk -v fn=$fn '{ 211 if (FNR == fn) { x="" } else { x=" \\" }; 212 printf "\t%s%s\n", $0, x; 213 }' 214 215 echo 216 list_fw | grep -v ^FWS | grep -v ^FWL | grep -v ^FWGET 217 218 echo 219 echo "DISTFILES_\${FWDRV}= \\" 220 for sz in ${fwsl}; do echo "${sz}"; done | \ 221 awk -v fn=$fn '{ 222 if (FNR == fn) { x="" } else { x=" \\" }; 223 printf "\t${DISTFILES_%s}%s\n", $0, x; 224 }' 225 226 fwsl=$(list_fw | grep ^FWL | awk '{ print $2 }') 227 # Get a count so we can automatically add \\ apart from the last line. 228 fn=$(echo "${fwsl}" | wc -w | awk '{ print $1 }') 229 if test ${fn} -gt 0; then 230 echo "DISTFILES_\${FWDRV}_lic= \\" 231 for sz in ${fwsl}; do echo "${sz}"; done | \ 232 awk -v fn=$fn '{ 233 if (FNR == fn) { x="" } else { x=" \\" }; 234 printf "\t${DISTFILES_%s_lic}%s\n", $0, x; 235 }' 236 else 237 echo "DISTFILES_\${FWDRV}_lic=" 238 fi 239 240 ) >> ${portsfile} 241 242 printf "INFO: wifi-firmware-%s-kmod template at %s\n" ${DRIVER} ${portsfile} >&2 243fi 244 245################################################################################ 246# 247# Generate the fwget(8) case pattern table (PCI device ID -> fw port flavor). 248# 249 250fwgetfile=$(mktemp -p /tmp ${DRIVER}-fwget.XXXXXX) 251:> ${fwgetfile} 252 253fwsl=$(list_fw | grep ^FWGET | sort) 254# Get a count so we can automatically add \\ apart from the last line. 255fn=$(echo "${fwsl}" | grep -c FWGET | awk '{ print $1 }') 256 257if test ${fn} -gt 0; then 258 259 # We need to check for same ID with multiple firmware. 260 # The list ist sorted by ID so duplicates are next to each other. 261 cs=$(echo "${fwsl}" | awk '{ print $2 }' | uniq -c | awk '{ print $1 }') 262 263 #echo "==> cs=${cs}" >&2 264 265 for n in ${cs}; do 266 267 # Skip FWGET 268 fwsl=${fwsl#*[[:space:]]} 269 # get device ID 270 did=${fwsl%%[[:space:]]*} 271 fwsl=${fwsl#*[[:space:]]} 272 # get flavor 273 flav=${fwsl%%[[:space:]]*} 274 fwsl=${fwsl#*[[:space:]]} 275 276 # printf "===> did %s flav %s\n" ${did} ${flav} >&2 277 278 if test ${n} -eq 1; then 279 echo "${did} ${flav}" | awk -v drv=${DRIVER} '{ 280 printf "\t%s)\taddpkg \"wifi-firmware-%s-kmod-%s\"; return 1 ;;\n", 281 tolower($1), drv, tolower($2); 282 }' >> ${fwgetfile} 283 else 284 echo "${did} ${flav}" | awk -v drv=${DRIVER} '{ 285 printf "\t%s)\taddpkg \"wifi-firmware-%s-kmod-%s\"\n", 286 tolower($1), drv, tolower($2); 287 }' >> ${fwgetfile} 288 289 i=1 290 while test ${i} -lt ${n}; do 291 # Skip FWGET 292 fwsl=${fwsl#*[[:space:]]} 293 # get device ID 294 did=${fwsl%%[[:space:]]*} 295 fwsl=${fwsl#*[[:space:]]} 296 # get flavor 297 flav=${fwsl%%[[:space:]]*} 298 fwsl=${fwsl#*[[:space:]]} 299 300 #printf "===> did %s flav %s\n" ${did} ${flav} >&2 301 302 echo "${did} ${flav}" | awk -v drv=${DRIVER} '{ 303 printf "\t\taddpkg \"wifi-firmware-%s-kmod-%s\"\n", 304 drv, tolower($2); 305 }' >> ${fwgetfile} 306 307 i=$((i + 1)) 308 done 309 310 printf "\t\treturn 1 ;;\n" >> ${fwgetfile} 311 fi 312 done 313fi 314 315printf "INFO: fwget pci_network_qca %s template at %s\n" ${DRIVER} ${fwgetfile} >&2 316 317# end 318