#!/bin/bash KERNEL_VER=3.10-rc6 D=drivers/gpu/drm/radeon # # optional: comment this out to use curl instead of git clone # #KERNEL_FROM_GIT=1 if [ ! -d linux ]; then if [ ${KERNEL_FROM_GIT:-0} -ne 0 ]; then echo "using git to get kernel sources" git clone http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git || exit 1 ( cd linux && git checkout v${KERNEL_VER} ) || exit 1 else echo "using tar.xz kernel sources" if ! which xz >/dev/null 2>&1; then echo "cannot find xz:" which xz exit 1 fi [ -f linux-${KERNEL_VER}.tar.xz ] || curl -O https://www.kernel.org/pub/linux/kernel/v3.x/testing/linux-${KERNEL_VER}.tar.xz || exit 1 xz -dc linux-${KERNEL_VER}.tar.xz | tar xf - || exit 1 mv linux-${KERNEL_VER} linux || exit 1 fi rm -f linux/tags fi if [ ! -f avert-func-name-collision.patch ]; then # # because linux/drivers/gpu/drm/radeon/radeon_drv.c defines static int __init radeon_init(void) also # change the name of the #define # cat <avert-func-name-collision.patch --- linux/drivers/gpu/drm/radeon/radeon.h 2013-06-20 16:22:44.000000000 -0600 +++ linux/drivers/gpu/drm/radeon/radeon.h 2013-06-20 16:22:55.000000000 -0600 @@ -1873,8 +1873,8 @@ /* * ASICs macro. */ -#define radeon_init(rdev) (rdev)->asic->init((rdev)) -#define radeon_fini(rdev) (rdev)->asic->fini((rdev)) +#define radeon_asic_p_init(rdev) (rdev)->asic->init((rdev)) +#define radeon_asic_p_fini(rdev) (rdev)->asic->fini((rdev)) #define radeon_resume(rdev) (rdev)->asic->resume((rdev)) #define radeon_suspend(rdev) (rdev)->asic->suspend((rdev)) #define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)].cs_parse((p)) --- linux/drivers/gpu/drm/radeon/radeon_device.c 2013-06-20 16:24:59.000000000 -0600 +++ linux/drivers/gpu/drm/radeon/radeon_device.c 2013-06-20 16:23:27.000000000 -0600 @@ -1176,7 +1176,7 @@ vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops); - r = radeon_init(rdev); + r = radeon_asic_p_init(rdev); if (r) return r; @@ -1194,9 +1194,9 @@ * with fallback to PCI or PCIE GART */ radeon_asic_reset(rdev); - radeon_fini(rdev); + radeon_asic_p_fini(rdev); radeon_agp_disable(rdev); - r = radeon_init(rdev); + r = radeon_asic_p_init(rdev); if (r) return r; } @@ -1228,7 +1228,7 @@ rdev->shutdown = true; /* evict vram memory */ radeon_bo_evict_vram(rdev); - radeon_fini(rdev); + radeon_asic_p_fini(rdev); vga_switcheroo_unregister_client(rdev->pdev); vga_client_register(rdev->pdev, NULL, NULL, NULL); if (rdev->rio_mem) EOF patch -p0 -i avert-func-name-collision.patch rm -f linux/tags fi if [ ! -f linux/tags ]; then echo "ctags -R linux" ( cd linux && ctags -R ) || exit 1 rm -f linux/"$D"/tags fi if [ ! -f linux/"$D"/tags ]; then echo "filter only $D/tags" AWK="`echo \"$D\" | awk '{gsub("/","\\\\/");print}'`" ( cd linux && awk "BEGIN{FS=\"\\t\"} { if (\$2 ~ /^${AWK}/) print }" tags > $D/tags ) || exit 1 fi whitelist_ops() { # # expand_whitelist will not find ops structures # in reality, there is just one that must be manually selected: 'struct radeon_asic' # and only one member needed for coreboot: .init # this also pulls in .hpd.init (HPD = hot plug detect) because it is not smart enough not to # # static struct radeon_asic trinity_asic = { # .init = &cayman_init, # .fini = &cayman_fini, # ... # ( echo "awk 'BEGIN{FS=\"\\t\";" awk '{ if (x) { if (match($0, "^[[:space:]]*\\.init[[:space:]]*=[[:space:]]&")) print "a[\"" gensub(",$", "", "", substr($0, RSTART+RLENGTH)) "\"]=1;"; c+=gsub("{",""); c-=gsub("}",""); if (!c) x=0 }; if ($0 ~ "^static struct radeon_asic.*=.*{") {x=1;c=gsub("{","");} }' "$D"/radeon_asic.c echo "}{n=3;while (!match(\$n, \";\\\"\$\") && n < NF) n++;n++;if (\$n==\"f\" && \$1 in a) print}' \"$D\"/tags" ) > "$D"/whitelist.sh || exit 1 ( cat "$D"/whitelist && . "$D"/whitelist.sh ) | sort -u > "$D"/whitelist.out rm -f "$D"/whitelist.sh mv "$D"/whitelist.out "$D"/whitelist } expand_whitelist() { # # 1. output the function bodies of all functions in the whitelist # 2. look up every C identifier in that text # 3. any C identifier found in tags (ctags output file) with $4=="f" is a function # 4. replace the whitelist with the new list # # step 1: function bodies awk 'BEGIN{FS="\t";print "#!/bin/bash"}{ sub("/\\^","\"",$3); sub("\\$/;\"$","\"",$3); print "awk '"'"'{if (x) {n=$0;c+=gsub(\"{\",\"\");c-=gsub(\"}\",\"\");print n;if (!c) x=0};" print " if ($0 == " $3 ") {x=1;c=0}}'"'"' " $2 }' "$D"/whitelist > "$D"/whitelist.sh . "$D"/whitelist.sh > "$D"/whitelist.out || exit 1 # step 2: C identifiers awk '{ s=$0; while (1) { gsub("\"[^\"]*\"","",s); if (!match(s, "[_A-Za-z][0-9_A-Za-z]*")) break; print "a[\"" substr(s,RSTART,RLENGTH) "\"]=1;"; s=substr(s,RSTART+RLENGTH); } }' "$D"/whitelist.out | sort -u > "$D"/whitelist.awk || exit 1 # step 3 and 4: functions ( echo "awk 'BEGIN{FS=\"\\t\";" cat "$D"/whitelist.awk echo "}{n=3;while (!match(\$n, \";\\\"\$\") && n < NF) n++;n++;if (\$n==\"f\" && \$1 in a) print}' \"$D\"/tags" ) > "$D"/whitelist.sh rm -f "$D"/whitelist.awk . "$D"/whitelist.sh > "$D"/whitelist.out || exit 1 cat "$D"/whitelist "$D"/whitelist.out | sort -u > "$D"/whitelist.sh || exit 1 mv "$D"/whitelist.sh "$D"/whitelist || exit 1 rm -f "$D"/whitelist.out } if [ ! -f linux/"$D"/whitelist ]; then echo "expand whitelist" ( cd linux || exit 1 grep '^\(radeon_driver_load_kms\|radeon_driver_open_kms\)' "$D"/tags > "$D"/whitelist || exit 1 whitelist_ops c=0 while true; do N="`awk 'END{print NR}' \"$D\"/whitelist`" echo -e "\e[A\e[Kexpand whitelist: $N" expand_whitelist M="`awk 'END{print NR}' \"$D\"/whitelist`" [ $M -eq $N ] && break done ) || exit 1 rm -f unused_funcs.spatch fi if [ ! -f unused_funcs.spatch ]; then echo "> unused_funcs.spatch" awk 'BEGIN{ print "@whitelist@"; print "@@"; s = "("; } { print s; print $1 "(...) {...}"; s = "|"; } END{ print ")"; print ""; print "@remove_other_funcs depends on !whitelist@"; print "identifier funcname"; print "@@"; print "<..."; print "-funcname(...) {...}"; print "...>"; }' linux/"$D"/whitelist > unused_funcs.spatch fi