[coreboot] Native init for AMD cards
David Hubbard
david.c.hubbard+coreboot at gmail.com
Fri Jun 21 04:15:43 CEST 2013
Hi Ron, Rudolf,
I've attached a shell script that does the first part of preparing the
in-kernel radeon driver for coreboot.
I settled on a shell script after thinking about what coccinelle is best
used for. It does look like coccinelle could do what ctags does, namely,
find function definitions. However ctags has the advantage of automatically
filtering out function calls that refer to any other part of the kernel
(ctags only lists where the function is *defined* in the 'tags' file it
outputs).
The output of this script is a coccinelle .spatch that I don't actually
expect to work yet. I'll become more confident with coccinelle as I use it
more. I wanted to send this as a question --
What do you think is the best way to slice up the in-kernel radeon driver?
This script relies on very few special cases which should hopefully make
the code reuse as painless as possible. The special cases:
1. Rename the #define radeon_init() in drivers/gpu/drm/radeon/radeon.h
2. Find struct radeon_asic initializers in
drivers/gpu/drm/radeon/radeon_asic.c
After this auto-generated coccinelle .spatch, the source tree needs manual
spatches applied to change kernel API calls to coreboot API calls. After
looking for any pitfalls, that would be the next thing to do.
Regards,
David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.coreboot.org/pipermail/coreboot/attachments/20130620/cbcc2d17/attachment.html>
-------------- next part --------------
#!/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 <<EOF >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
More information about the coreboot
mailing list