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
#!/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
-- 
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to