Add a simple structure and search function to the common code that can be used for looking up a set of addresses by type. The user must supply the iomaps[] table, e.g. struct iomap iomaps[] = { { .type = "virtio_mmio", .nr = 4, .addrs = { 0x2000000, 0x2000200, 0x2000400, 0x2000600, }, }, { .type = NULL, }, }; Also add a script scripts/gen-devtree-iomaps.pl that can generate the iomaps table from an fdt, e.g. fdtdump dtb | scripts/gen-devtree-iomaps.pl - virtio_mmio Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx> --- v2: - switch to kernel coding style - rework fdt parsing to enable extraction of properties. Extract the 'compatible' property. - add iomaps_find_compatible() to allow searching for iomaps by its 'compatible' property. --- README | 1 + lib/iomaps.c | 31 +++++++++++++ lib/iomaps.h | 14 ++++++ scripts/gen-devtree-iomaps.pl | 105 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 lib/iomaps.c create mode 100644 lib/iomaps.h create mode 100755 scripts/gen-devtree-iomaps.pl diff --git a/README b/README index 0174679c05021..f834c61dc6112 100644 --- a/README +++ b/README @@ -20,6 +20,7 @@ Directory structure: .: Makefile and config files for the tests ./config: config files for the tests ./docs: documentation files +./scripts: misc helper scripts ./lib: general services for the tests ./lib/<ARCH>: architecture dependent services for the tests ./<ARCH>: the sources of the tests and the created objects/images diff --git a/lib/iomaps.c b/lib/iomaps.c new file mode 100644 index 0000000000000..f2263b79dce96 --- /dev/null +++ b/lib/iomaps.c @@ -0,0 +1,31 @@ +#include "libcflat.h" +#include "iomaps.h" + +extern const struct iomap iomaps[]; + +const struct iomap *iomaps_find_type(const char *type) +{ + const struct iomap *m = &iomaps[0]; + + while (m->type) { + if (strcmp(m->type, type) == 0) + return m; + ++m; + } + return NULL; +} + +const struct iomap *iomaps_find_compatible(const char *compat) +{ + const struct iomap *m = &iomaps[0]; + const char *c; + int i; + + while (m->type) { + for (i = 0, c = m->compats[0]; c != NULL; c = m->compats[++i]) + if (strcmp(c, compat) == 0) + return m; + ++m; + } + return NULL; +} diff --git a/lib/iomaps.h b/lib/iomaps.h new file mode 100644 index 0000000000000..76a1aa4720337 --- /dev/null +++ b/lib/iomaps.h @@ -0,0 +1,14 @@ +#ifndef _IOMAPS_H_ +#define _IOMAPS_H_ +#include "libcflat.h" + +struct iomap { + const char *type; + const char *compats[5]; + u32 nr; + u32 addrs[64]; +}; + +const struct iomap *iomaps_find_type(const char *type); +const struct iomap *iomaps_find_compatible(const char *compat); +#endif diff --git a/scripts/gen-devtree-iomaps.pl b/scripts/gen-devtree-iomaps.pl new file mode 100755 index 0000000000000..b48e85e48ab34 --- /dev/null +++ b/scripts/gen-devtree-iomaps.pl @@ -0,0 +1,105 @@ +#!/usr/bin/perl -w +use strict; +use File::Temp qw/:POSIX/; + +my $dts = shift @ARGV; +my @types = @ARGV; +my $max_nr_addrs = 64; +my $max_nr_compats = 4; + +if (!defined $dts || $#types < 0) { + print STDERR "Usage: gen-devtree-iomaps ". + "<dts-file|-> <addr-type> [addr-types...]\n"; + exit 1; +} + +my $dtb = tmpnam(); +system "dtc -I dts -O dtb $dts -o $dtb"; + +my $g = join '|', map { $_ . '@' } @types; +my @devs = grep { /$g/ } `fdtget -l $dtb / 2>/dev/null`; + +my %iomaps; +foreach my $dev (@devs) { + + chomp($dev); + my ($type, $addr) = split /@/, $dev; + + if (!exists $iomaps{$type}) { + + my $compatible = `fdtget $dtb /$dev compatible 2>/dev/null`; + chomp($compatible); + my @compats = split ' ', $compatible; + + $iomaps{$type}{compats} = \@compats; + $iomaps{$type}{addrs} = [$addr]; + } else { + push @{ $iomaps{$type}{addrs} }, $addr; + } +} +unlink $dtb; + +print <<EOF; +/* + * Generated file. See gen-devtree-iomaps.pl + */ +#include "iomaps.h" +EOF +print "\nconst struct iomap iomaps[] = {\n"; +foreach my $type (keys %iomaps) { + + my $compats = $iomaps{$type}{compats}; + my $addrs = $iomaps{$type}{addrs}; + + my $nr_compats = $#{ $compats } + 1; + if ($nr_compats > $max_nr_compats) { + print STDERR "$type has $nr_compats compats, but iomaps can ". + "only support up to $max_nr_compats.\n"; + splice @{ $compats }, $max_nr_compats; + } + + @{ $addrs } = sort @{ $addrs }; + + my $nr = $#{ $addrs } + 1; + if ($nr > $max_nr_addrs) { + print STDERR "$type has $nr addrs, but iomaps can ". + "only support up to $max_nr_addrs.\n"; + $nr = $max_nr_addrs; + splice @{ $addrs }, $nr; + } + + @{ $addrs } = map { $_ = sprintf '0x%.8x', hex($_) } @{ $addrs }; + + print "{\n"; + print "\t.type = \"$type\",\n"; + + print "\t.compats = {"; + foreach my $compat (@{ $compats }) { + print " \"$compat\","; + } + print " NULL, },\n"; + + print "\t.nr = $nr,\n"; + print "\t.addrs = {"; + if ($nr < 5) { + print ' '; + print join ', ', @{ $addrs }; + print ", },\n"; + } else { + print "\n"; + for (my $i = 0; $i < $nr; $i += 5) { + print "\t\t"; + my $j = $i; + while ($j < $i + 4 && $j < $nr - 1) { + print $addrs->[$j] . ", "; + ++$j; + } + print $addrs->[$j] . ",\n"; + } + print "\t},\n"; + } + print "},\n"; +} +print "{\n\t.type = NULL,\n},\n"; +print "};\n"; +exit 0; -- 1.8.1.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html