From aeae1e92daec5a38b40ad12598b97501b675a381 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 3 Jul 2011 21:41:33 -0400 Subject: [PATCH 0001/1596] tools/power turbostat: less verbose debugging dump only the counters which are active Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 28 ++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 6d8ef4a3a9b5..dd2d1a2bdae9 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -162,19 +162,21 @@ void print_header(void) void dump_cnt(struct counters *cnt) { - fprintf(stderr, "package: %d ", cnt->pkg); - fprintf(stderr, "core:: %d ", cnt->core); - fprintf(stderr, "CPU: %d ", cnt->cpu); - fprintf(stderr, "TSC: %016llX\n", cnt->tsc); - fprintf(stderr, "c3: %016llX\n", cnt->c3); - fprintf(stderr, "c6: %016llX\n", cnt->c6); - fprintf(stderr, "c7: %016llX\n", cnt->c7); - fprintf(stderr, "aperf: %016llX\n", cnt->aperf); - fprintf(stderr, "pc2: %016llX\n", cnt->pc2); - fprintf(stderr, "pc3: %016llX\n", cnt->pc3); - fprintf(stderr, "pc6: %016llX\n", cnt->pc6); - fprintf(stderr, "pc7: %016llX\n", cnt->pc7); - fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); + if (!cnt) + return; + if (cnt->pkg) fprintf(stderr, "package: %d ", cnt->pkg); + if (cnt->core) fprintf(stderr, "core:: %d ", cnt->core); + if (cnt->cpu) fprintf(stderr, "CPU: %d ", cnt->cpu); + if (cnt->tsc) fprintf(stderr, "TSC: %016llX\n", cnt->tsc); + if (cnt->c3) fprintf(stderr, "c3: %016llX\n", cnt->c3); + if (cnt->c6) fprintf(stderr, "c6: %016llX\n", cnt->c6); + if (cnt->c7) fprintf(stderr, "c7: %016llX\n", cnt->c7); + if (cnt->aperf) fprintf(stderr, "aperf: %016llX\n", cnt->aperf); + if (cnt->pc2) fprintf(stderr, "pc2: %016llX\n", cnt->pc2); + if (cnt->pc3) fprintf(stderr, "pc3: %016llX\n", cnt->pc3); + if (cnt->pc6) fprintf(stderr, "pc6: %016llX\n", cnt->pc6); + if (cnt->pc7) fprintf(stderr, "pc7: %016llX\n", cnt->pc7); + if (cnt->extra_msr) fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); } void dump_list(struct counters *cnt) From e882dc9c8e10db52dd509fbd67240ce0cc09c201 Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:15:59 +0300 Subject: [PATCH 0002/1596] Xen: fix whitespaces,tabs coding style issue in drivers/xen/balloon.c This is a patch to the balloon.c file that fixed up whitespaces, tabs errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index f54290baa3db..61c0ee7aa7dd 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -84,8 +84,8 @@ static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; #define inc_totalhigh_pages() (totalhigh_pages++) #define dec_totalhigh_pages() (totalhigh_pages--) #else -#define inc_totalhigh_pages() do {} while(0) -#define dec_totalhigh_pages() do {} while(0) +#define inc_totalhigh_pages() do {} while (0) +#define dec_totalhigh_pages() do {} while (0) #endif /* List of ballooned pages, threaded through the mem_map array. */ @@ -145,8 +145,7 @@ static struct page *balloon_retrieve(bool prefer_highmem) if (PageHighMem(page)) { balloon_stats.balloon_high--; inc_totalhigh_pages(); - } - else + } else balloon_stats.balloon_low--; totalram_pages++; @@ -299,7 +298,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) (unsigned long)__va(pfn << PAGE_SHIFT), __pte_ma(0), 0); BUG_ON(ret); - } + } } @@ -376,10 +375,10 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target); * @pages: pages returned * @return 0 on success, error otherwise */ -int alloc_xenballooned_pages(int nr_pages, struct page** pages) +int alloc_xenballooned_pages(int nr_pages, struct page **pages) { int pgno = 0; - struct page* page; + struct page *page; mutex_lock(&balloon_mutex); while (pgno < nr_pages) { page = balloon_retrieve(true); @@ -409,7 +408,7 @@ EXPORT_SYMBOL(alloc_xenballooned_pages); * @nr_pages: Number of pages * @pages: pages to return */ -void free_xenballooned_pages(int nr_pages, struct page** pages) +void free_xenballooned_pages(int nr_pages, struct page **pages) { int i; From 088c05a845da821fba9e5434bbcc6329368de34e Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:16:13 +0300 Subject: [PATCH 0003/1596] Xen: fix whitespaces,tabs coding style issue in drivers/xen/events.c This is a patch to the events.c file that fixed up whitespaces, tabs and braces errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index da70f5c32eb9..8876ffd08771 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -85,8 +85,7 @@ enum xen_irq_type { * IPI - IPI vector * EVTCHN - */ -struct irq_info -{ +struct irq_info { struct list_head list; enum xen_irq_type type; /* type */ unsigned irq; @@ -282,9 +281,9 @@ static inline unsigned long active_evtchns(unsigned int cpu, struct shared_info *sh, unsigned int idx) { - return (sh->evtchn_pending[idx] & + return sh->evtchn_pending[idx] & per_cpu(cpu_evtchn_mask, cpu)[idx] & - ~sh->evtchn_mask[idx]); + ~sh->evtchn_mask[idx]; } static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) @@ -1152,7 +1151,7 @@ static void __xen_evtchn_do_upcall(void) int cpu = get_cpu(); struct shared_info *s = HYPERVISOR_shared_info; struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); - unsigned count; + unsigned count; do { unsigned long pending_words; From 7b0ac956d91b91a1e05e4e0b454d65710fc73cd8 Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:16:26 +0300 Subject: [PATCH 0004/1596] Xen: fix braces coding style issue in gntdev.c and grant-table.c This is a patch to the gntdev.c and grant-table.c files that fixed up braces errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 3 +-- drivers/xen/grant-table.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index f914b26cf0c2..772a5b8bbf2e 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -188,9 +188,8 @@ static void gntdev_put_map(struct grant_map *map) atomic_sub(map->count, &pages_mapped); - if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) { + if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) notify_remote_via_evtchn(map->notify.event); - } if (map->pages) { if (!use_ptemod) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index fd725cde6ad1..3a3dceb7063a 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -193,7 +193,7 @@ int gnttab_query_foreign_access(grant_ref_t ref) nflags = shared[ref].flags; - return (nflags & (GTF_reading|GTF_writing)); + return nflags & (GTF_reading|GTF_writing); } EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); From 4b0109830842fa645c7f7460dc713cedfe4473f6 Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:16:38 +0300 Subject: [PATCH 0005/1596] Xen: fix whitespaces,tabs coding style issue in drivers/xen/pci.c This is a patch to the pci.c file that fixed up whitespaces, tabs warnings found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c index cef4bafc07dc..c4448ee5595f 100644 --- a/drivers/xen/pci.c +++ b/drivers/xen/pci.c @@ -36,7 +36,7 @@ static int xen_add_device(struct device *dev) struct physdev_manage_pci_ext manage_pci_ext = { .bus = pci_dev->bus->number, .devfn = pci_dev->devfn, - .is_virtfn = 1, + .is_virtfn = 1, .physfn.bus = pci_dev->physfn->bus->number, .physfn.devfn = pci_dev->physfn->devfn, }; @@ -56,7 +56,7 @@ static int xen_add_device(struct device *dev) &manage_pci_ext); } else { struct physdev_manage_pci manage_pci = { - .bus = pci_dev->bus->number, + .bus = pci_dev->bus->number, .devfn = pci_dev->devfn, }; From 822a259aa17e977892bf9dbb546522c477f7b7cb Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:17:01 +0300 Subject: [PATCH 0006/1596] Xen: fix braces coding style issue in xenbus_probe.h This is a patch to the xenbus_probe.h file that fixed up braces errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index b814935378c7..9b1de4e34c64 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h @@ -36,8 +36,7 @@ #define XEN_BUS_ID_SIZE 20 -struct xen_bus_type -{ +struct xen_bus_type { char *root; unsigned int levels; int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename); From 6913200a566b6d2866d46d7b947a2326c4e11f55 Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:17:23 +0300 Subject: [PATCH 0007/1596] Xen: fix braces and tabs coding style issue in xenbus_probe.c This is a patch to the xenbus_probe.c file that fixed up braces and tabs errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index bd2f90c9ac8b..d4c7a9ffbcb9 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -309,8 +309,7 @@ void xenbus_unregister_driver(struct xenbus_driver *drv) } EXPORT_SYMBOL_GPL(xenbus_unregister_driver); -struct xb_find_info -{ +struct xb_find_info { struct xenbus_device *dev; const char *nodename; }; @@ -639,7 +638,7 @@ int xenbus_dev_cancel(struct device *dev) EXPORT_SYMBOL_GPL(xenbus_dev_cancel); /* A flag to determine if xenstored is 'ready' (i.e. has started) */ -int xenstored_ready = 0; +int xenstored_ready; int register_xenstore_notifier(struct notifier_block *nb) @@ -762,7 +761,7 @@ static int __init xenbus_init(void) return 0; - out_error: +out_error: if (page != 0) free_page(page); From 6b71c52e7f848e2c9f804e175215e5965ea90d32 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 28 Jul 2011 15:23:03 +0200 Subject: [PATCH 0008/1596] xen: use static initializers in xen-balloon.c There is no need to use dynamic initializaion, it just confuses the reader. Switch to static initializers like its used in other files. Signed-off-by: Olaf Hering [v2: Rebased on v3.0] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xen-balloon.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index 5c9dc43c1e94..9cc2259c9992 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c @@ -50,11 +50,6 @@ static struct sys_device balloon_sysdev; static int register_balloon(struct sys_device *sysdev); -static struct xenbus_watch target_watch = -{ - .node = "memory/target" -}; - /* React to a change in the target key */ static void watch_target(struct xenbus_watch *watch, const char **vec, unsigned int len) @@ -73,6 +68,11 @@ static void watch_target(struct xenbus_watch *watch, */ balloon_set_new_target(new_target >> (PAGE_SHIFT - 10)); } +static struct xenbus_watch target_watch = { + .node = "memory/target", + .callback = watch_target, +}; + static int balloon_init_watcher(struct notifier_block *notifier, unsigned long event, @@ -87,7 +87,9 @@ static int balloon_init_watcher(struct notifier_block *notifier, return NOTIFY_DONE; } -static struct notifier_block xenstore_notifier; +static struct notifier_block xenstore_notifier = { + .notifier_call = balloon_init_watcher, +}; static int __init balloon_init(void) { @@ -100,9 +102,6 @@ static int __init balloon_init(void) register_xen_selfballooning(&balloon_sysdev); - target_watch.callback = watch_target; - xenstore_notifier.notifier_call = balloon_init_watcher; - register_xenstore_notifier(&xenstore_notifier); return 0; From f597a718296eef9622ebc1d13f4f8324fa169cef Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Fri, 1 Jul 2011 17:45:31 -0400 Subject: [PATCH 0009/1596] kconfig/streamline_config.pl: directly access LSMOD from the environment Cc: Steven Rostedt Signed-off-by: Arnaud Lacombe --- scripts/kconfig/Makefile | 12 ++---------- scripts/kconfig/streamline_config.pl | 8 ++++++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 82d2eb285b70..bd41ab29e680 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -33,17 +33,9 @@ silentoldconfig: $(obj)/conf $(Q)mkdir -p include/generated $< --$@ $(Kconfig) -# if no path is given, then use src directory to find file -ifdef LSMOD -LSMOD_F := $(LSMOD) -ifeq ($(findstring /,$(LSMOD)),) - LSMOD_F := $(objtree)/$(LSMOD) -endif -endif - localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config + $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ (mv -f .config .config.old.1; \ @@ -58,7 +50,7 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf localyesconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config + $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config $(Q)sed -i s/=m/=y/ .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index a4fe923c0131..ae34d2007f57 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -115,7 +115,7 @@ sub find_config { # Get the build source and top level Kconfig file (passed in) my $ksource = $ARGV[0]; my $kconfig = $ARGV[1]; -my $lsmod_file = $ARGV[2]; +my $lsmod_file = $ENV{'LSMOD'}; my @makefiles = `find $ksource -name Makefile 2>/dev/null`; chomp @makefiles; @@ -296,7 +296,11 @@ sub read_kconfig { if (defined($lsmod_file)) { if ( ! -f $lsmod_file) { - die "$lsmod_file not found"; + if ( -f $ENV{'objtree'}."/".$lsmod_file) { + $lsmod_file = $ENV{'objtree'}."/".$lsmod_file; + } else { + die "$lsmod_file not found"; + } } if ( -x $lsmod_file) { # the file is executable, run it From 22d550ae83603aa8d64d72dd1e2309cd7a96ac89 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Wed, 20 Jul 2011 00:40:09 -0400 Subject: [PATCH 0010/1596] kconfig/streamline_config.pl: use options to determine operating mode The options introduced are --localmodconfig (default) and --localyesconfig. They match the Makefile target behavior. Cc: Steven Rostedt Signed-off-by: Arnaud Lacombe --- scripts/kconfig/Makefile | 4 ++-- scripts/kconfig/streamline_config.pl | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index bd41ab29e680..4de89738827c 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -35,7 +35,7 @@ silentoldconfig: $(obj)/conf localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ (mv -f .config .config.old.1; \ @@ -50,7 +50,7 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf localyesconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)sed -i s/=m/=y/ .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index ae34d2007f57..ec7afce4c88d 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -43,6 +43,7 @@ # make oldconfig # use strict; +use Getopt::Long; my $config = ".config"; @@ -112,6 +113,13 @@ sub find_config { find_config; +# Parse options +my $localmodconfig = 0; +my $localyesconfig = 0; + +GetOptions("localmodconfig" => \$localmodconfig, + "localyesconfig" => \$localyesconfig); + # Get the build source and top level Kconfig file (passed in) my $ksource = $ARGV[0]; my $kconfig = $ARGV[1]; @@ -425,7 +433,11 @@ sub parse_config_dep_select if (/^(CONFIG.*)=(m|y)/) { if (defined($configs{$1})) { - $setconfigs{$1} = $2; + if ($localyesconfig) { + $setconfigs{$1} = 'y'; + } else { + $setconfigs{$1} = $2; + } } elsif ($2 eq "m") { print "# $1 is not set\n"; next; From 50bce3e80773e06316fcb92796ff26b42348d30b Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Fri, 1 Jul 2011 18:13:03 -0400 Subject: [PATCH 0011/1596] kconfig/streamline_config.pl: merge local{mod,yes}config The two targets `localmodconfig' and `localyesconfig' only differs from the sed(1) ran on the result of `streamline_config.pl' to convert symbols set to `modules' to `yes'. This conversion can be made directly from the perl script, and thus avoid duplicating the command to generate the configuration. Cc: Steven Rostedt Signed-off-by: Arnaud Lacombe --- scripts/kconfig/Makefile | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 4de89738827c..ba573fe7c74d 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -33,7 +33,7 @@ silentoldconfig: $(obj)/conf $(Q)mkdir -p include/generated $< --$@ $(Kconfig) -localmodconfig: $(obj)/streamline_config.pl $(obj)/conf +localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ @@ -48,22 +48,6 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf fi $(Q)rm -f .tmp.config -localyesconfig: $(obj)/streamline_config.pl $(obj)/conf - $(Q)mkdir -p include/generated - $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config - $(Q)sed -i s/=m/=y/ .tmp.config - $(Q)if [ -f .config ]; then \ - cmp -s .tmp.config .config || \ - (mv -f .config .config.old.1; \ - mv -f .tmp.config .config; \ - $(obj)/conf --silentoldconfig $(Kconfig); \ - mv -f .config.old.1 .config.old) \ - else \ - mv -f .tmp.config .config; \ - $(obj)/conf --silentoldconfig $(Kconfig); \ - fi - $(Q)rm -f .tmp.config - # Create new linux.pot file # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files # The symlink is used to repair a deficiency in arch/um From 13049537007dee73a76f0a30fcbc24d02c6fa9e4 Mon Sep 17 00:00:00 2001 From: Joseph Handzik Date: Mon, 8 Aug 2011 11:40:15 +0200 Subject: [PATCH 0012/1596] cciss: Adds simple mode functionality Signed-off-by: Joseph Handzik Acked-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- Documentation/blockdev/cciss.txt | 10 ++++++ drivers/block/cciss.c | 56 +++++++++++++++++++++++++------- drivers/block/cciss.h | 1 + 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/Documentation/blockdev/cciss.txt b/Documentation/blockdev/cciss.txt index c00c6a5ab21f..71464e09ec18 100644 --- a/Documentation/blockdev/cciss.txt +++ b/Documentation/blockdev/cciss.txt @@ -78,6 +78,16 @@ The device naming scheme is: /dev/cciss/c1d1p2 Controller 1, disk 1, partition 2 /dev/cciss/c1d1p3 Controller 1, disk 1, partition 3 +CCISS simple mode support +------------------------- + +The "cciss_simple_mode=1" boot parameter may be used to prevent the driver +from putting the controller into "performant" mode. The difference is that +with simple mode, each command completion requires an interrupt, while with +"performant mode" (the default, and ordinarily better performing) it is +possible to have multiple command completions indicated by a single +interrupt. + SCSI tape drive and medium changer support ------------------------------------------ diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 8f4ef656a1af..61f0b5b6a415 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -68,6 +68,10 @@ static int cciss_tape_cmds = 6; module_param(cciss_tape_cmds, int, 0644); MODULE_PARM_DESC(cciss_tape_cmds, "number of commands to allocate for tape devices (default: 6)"); +static int cciss_simple_mode; +module_param(cciss_simple_mode, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(cciss_simple_mode, + "Use 'simple mode' rather than 'performant mode'"); static DEFINE_MUTEX(cciss_mutex); static struct proc_dir_entry *proc_cciss; @@ -176,6 +180,7 @@ static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol, unsigned int block_size, InquiryData_struct *inq_buff, drive_info_struct *drv); static void __devinit cciss_interrupt_mode(ctlr_info_t *); +static int __devinit cciss_enter_simple_mode(struct ctlr_info *h); static void start_io(ctlr_info_t *h); static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size, __u8 page_code, unsigned char scsi3addr[], @@ -388,7 +393,7 @@ static void cciss_seq_show_header(struct seq_file *seq) h->product_name, (unsigned long)h->board_id, h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], - h->firm_ver[3], (unsigned int)h->intr[PERF_MODE_INT], + h->firm_ver[3], (unsigned int)h->intr[h->intr_mode], h->num_luns, h->Qdepth, h->commands_outstanding, h->maxQsinceinit, h->max_outstanding, h->maxSG); @@ -3984,6 +3989,9 @@ static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) { __u32 trans_support; + if (cciss_simple_mode) + return; + dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n"); /* Attempt to put controller into performant mode if supported */ /* Does board support performant mode? */ @@ -4081,7 +4089,7 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *h) default_int_mode: #endif /* CONFIG_PCI_MSI */ /* if we get here we're going to use the default interrupt mode */ - h->intr[PERF_MODE_INT] = h->pdev->irq; + h->intr[h->intr_mode] = h->pdev->irq; return; } @@ -4341,6 +4349,9 @@ static int __devinit cciss_pci_init(ctlr_info_t *h) } cciss_enable_scsi_prefetch(h); cciss_p600_dma_prefetch_quirk(h); + err = cciss_enter_simple_mode(h); + if (err) + goto err_out_free_res; cciss_put_controller_into_performant_mode(h); return 0; @@ -4843,20 +4854,20 @@ static int cciss_request_irq(ctlr_info_t *h, irqreturn_t (*intxhandler)(int, void *)) { if (h->msix_vector || h->msi_vector) { - if (!request_irq(h->intr[PERF_MODE_INT], msixhandler, + if (!request_irq(h->intr[h->intr_mode], msixhandler, IRQF_DISABLED, h->devname, h)) return 0; dev_err(&h->pdev->dev, "Unable to get msi irq %d" - " for %s\n", h->intr[PERF_MODE_INT], + " for %s\n", h->intr[h->intr_mode], h->devname); return -1; } - if (!request_irq(h->intr[PERF_MODE_INT], intxhandler, + if (!request_irq(h->intr[h->intr_mode], intxhandler, IRQF_DISABLED, h->devname, h)) return 0; dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n", - h->intr[PERF_MODE_INT], h->devname); + h->intr[h->intr_mode], h->devname); return -1; } @@ -4887,7 +4898,7 @@ static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h) { int ctlr = h->ctlr; - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); #ifdef CONFIG_PCI_MSI if (h->msix_vector) pci_disable_msix(h->pdev); @@ -4953,6 +4964,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, h = hba[i]; h->pdev = pdev; h->busy_initializing = 1; + h->intr_mode = cciss_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; INIT_LIST_HEAD(&h->cmpQ); INIT_LIST_HEAD(&h->reqQ); mutex_init(&h->busy_shutting_down); @@ -5009,7 +5021,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n", h->devname, pdev->device, pci_name(pdev), - h->intr[PERF_MODE_INT], dac ? "" : " not"); + h->intr[h->intr_mode], dac ? "" : " not"); if (cciss_allocate_cmd_pool(h)) goto clean4; @@ -5056,7 +5068,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, spin_lock_irqsave(&h->lock, flags); h->access.set_intr_mask(h, CCISS_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); rc = cciss_request_irq(h, cciss_msix_discard_completions, cciss_intx_discard_completions); if (rc) { @@ -5133,7 +5145,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, cciss_free_cmd_pool(h); cciss_free_scatterlists(h); cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); clean2: unregister_blkdev(h->major, h->devname); clean1: @@ -5172,9 +5184,31 @@ static void cciss_shutdown(struct pci_dev *pdev) if (return_code != IO_OK) dev_warn(&h->pdev->dev, "Error flushing cache\n"); h->access.set_intr_mask(h, CCISS_INTR_OFF); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); } +static int __devinit cciss_enter_simple_mode(struct ctlr_info *h) +{ + u32 trans_support; + + trans_support = readl(&(h->cfgtable->TransportSupport)); + if (!(trans_support & SIMPLE_MODE)) + return -ENOTSUPP; + + h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); + writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + cciss_wait_for_mode_change_ack(h); + print_cfg_table(h); + if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { + dev_warn(&h->pdev->dev, "unable to get board into simple mode\n"); + return -ENODEV; + } + h->transMethod = CFGTBL_Trans_Simple; + return 0; +} + + static void __devexit cciss_remove_one(struct pci_dev *pdev) { ctlr_info_t *h; diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index c049548e68b7..7fda30e4a241 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -92,6 +92,7 @@ struct ctlr_info unsigned int intr[4]; unsigned int msix_vector; unsigned int msi_vector; + int intr_mode; int cciss_max_sectors; BYTE cciss_read; BYTE cciss_write; From f963d270cb7bbb8eeb57901d02b22a493e664fd2 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 8 Aug 2011 11:40:17 +0200 Subject: [PATCH 0013/1596] cciss: add transport mode attribute to sys Signed-off-by: Joseph Handzik Acked-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- .../ABI/testing/sysfs-bus-pci-devices-cciss | 7 +++++++ drivers/block/cciss.c | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss index f5bb0a3bb8c0..53d99edd1d75 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss @@ -71,3 +71,10 @@ Description: Value of 1 indicates the controller can honor the reset_devices a dump device, as kdump requires resetting the device in order to work reliably. +Where: /sys/bus/pci/devices//ccissX/transport_mode +Date: July 2011 +Kernel Version: 3.0 +Contact: iss_storagedev@hp.com +Description: Value of "simple" indicates that the controller has been placed + in "simple mode". Value of "performant" indicates that the + controller has been placed in "performant mode". diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 61f0b5b6a415..6da7edea700a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -641,6 +641,18 @@ static ssize_t host_store_rescan(struct device *dev, } static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); +static ssize_t host_show_transport_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ctlr_info *h = to_hba(dev); + + return snprintf(buf, 20, "%s\n", + h->transMethod & CFGTBL_Trans_Performant ? + "performant" : "simple"); +} +static DEVICE_ATTR(transport_mode, S_IRUGO, host_show_transport_mode, NULL); + static ssize_t dev_show_unique_id(struct device *dev, struct device_attribute *attr, char *buf) @@ -813,6 +825,7 @@ static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL); static struct attribute *cciss_host_attrs[] = { &dev_attr_rescan.attr, &dev_attr_resettable.attr, + &dev_attr_transport_mode.attr, NULL }; From 90b44f8ffdf6c66d190ee71b330009bf7f11a208 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 25 Jul 2011 19:57:52 +0530 Subject: [PATCH 0014/1596] dmaengine: add helper function for slave_single For clients which require a single slave transfer and dont want to be bothered about the scatterlist api, this helper gives simple API for this transfer and creates single scatterlist for DMA API Idea from Russell King Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 8fbf40e0713c..0d738c95fe4e 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -24,6 +24,7 @@ #include #include #include +#include struct scatterlist; @@ -519,6 +520,16 @@ static inline int dmaengine_slave_config(struct dma_chan *chan, (unsigned long)config); } +static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single( + struct dma_chan *chan, void *buf, size_t len, + enum dma_data_direction dir, unsigned long flags) +{ + struct scatterlist sg; + sg_init_one(&sg, buf, len); + + return chan->device->device_prep_slave_sg(chan, &sg, 1, dir, flags); +} + static inline int dmaengine_terminate_all(struct dma_chan *chan) { return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); From 4920e05c79417f9a8d236a044502e10729af91b3 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Wed, 3 Aug 2011 21:52:06 -0400 Subject: [PATCH 0015/1596] kconfig/nconf: nuke unreferenced `nohelp_text' After commit 5416857867c9cc94aba641898c567d9707de30f1, nohelp_text' is no longer referenced, nuke it. Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/nconf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 39ca1f1640ea..b113c50209e3 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -182,8 +182,6 @@ setmod_text[] = N_( "This feature depends on another which\n" "has been configured as a module.\n" "As a result, this feature will be built as a module."), -nohelp_text[] = N_( -"There is no help available for this option.\n"), load_config_text[] = N_( "Enter the name of the configuration file you wish to load.\n" "Accept the name shown to restore the configuration you\n" From 3f198dfee49d2e9c30583c62b0c79286c78c7b44 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 2 Aug 2011 18:49:52 +0100 Subject: [PATCH 0016/1596] kbuild: Fix help text not displayed in choice option. Help text under choice menu is never displayed because it does not have symbol name associated with it, however many kconfigs have help text under choice, assuming that it will be displayed when user selects help. for example in Kconfig if we have: choice prompt "Choice" ---help--- HELP TEXT ... config A bool "A" config B bool "B" endchoice Without this patch "HELP TEXT" is not displayed when user selects help option when "Choice" is highlighted from menuconfig or xconfig or gconfig. This patch changes the logic in menu_get_ext_help to display help for cases which dont have symbol names like choice. Signed-off-by: Srinivas Kandagatla Reviewed-by: Stuart Menefy Reviewed-by: Arnaud Lacombe Cc: stable@kernel.org Signed-off-by: Michal Marek --- scripts/kconfig/menu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index d66008639a43..beeb92e75f8f 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -597,11 +597,10 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) struct symbol *sym = menu->sym; if (menu_has_help(menu)) { - if (sym->name) { + if (sym->name) str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); - str_append(help, _(menu_get_help(menu))); - str_append(help, "\n"); - } + str_append(help, _(menu_get_help(menu))); + str_append(help, "\n"); } else { str_append(help, nohelp_text); } From 9704efaa52ab18eb3504c4e0bc421c1d01b7981a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 29 Jul 2011 16:21:57 +0530 Subject: [PATCH 0017/1596] dmaengine/dmatest: Terminate transfers on all channels in case of error or exit In case, some error occurs while doing memcpy transfers, we must terminate all transfers physically too. This is achieved by calling device_control() routine with TERMINATE_ALL as parameter. This is also required to be done in case module is removed while we are in middle of some transfers. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dmatest.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 765f5ff22304..accc18441b16 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -477,6 +477,8 @@ static int dmatest_func(void *data) pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", thread_name, total_tests, failed_tests, ret); + /* terminate all transfers on specified channels */ + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); if (iterations > 0) while (!kthread_should_stop()) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit); @@ -499,6 +501,10 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) list_del(&thread->node); kfree(thread); } + + /* terminate all transfers on specified channels */ + dtc->chan->device->device_control(dtc->chan, DMA_TERMINATE_ALL, 0); + kfree(dtc); } From 57e6292da67c30acf92f08604f918192a886838a Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Wed, 3 Aug 2011 21:52:07 -0400 Subject: [PATCH 0018/1596] kconfig: factor code in menu_get_ext_help() Cc: Srinivas Kandagatla Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/menu.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index beeb92e75f8f..8c2a97e60faf 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -10,8 +10,7 @@ #include "lkc.h" -static const char nohelp_text[] = N_( - "There is no help available for this option.\n"); +static const char nohelp_text[] = "There is no help available for this option."; struct menu rootmenu; static struct menu **last_entry_ptr; @@ -595,15 +594,14 @@ struct gstr get_relations_str(struct symbol **sym_arr) void menu_get_ext_help(struct menu *menu, struct gstr *help) { struct symbol *sym = menu->sym; + const char *help_text = nohelp_text; if (menu_has_help(menu)) { if (sym->name) str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); - str_append(help, _(menu_get_help(menu))); - str_append(help, "\n"); - } else { - str_append(help, nohelp_text); + help_text = menu_get_help(menu); } + str_printf(help, "%s\n", _(help_text)); if (sym) get_symbol_str(help, sym); } From f4b129f519f1bbd191dca2bf17d1137edf941fd1 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Wed, 10 Aug 2011 13:10:20 +0200 Subject: [PATCH 0019/1596] kbuild: Do not delete empty files in make distclean Commit 3d64b44 introduced an empty file under arch/arm/mach-zynq/board_dt.c. While this was not intended and the file was removed from the tree by a later commit, we really should only match junk files by known name patterns and not their size. Reported-by: David Howells Signed-off-by: Michal Marek --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b4ca4e111c9a..d714838d0a3a 100644 --- a/Makefile +++ b/Makefile @@ -1198,7 +1198,7 @@ distclean: mrproper @find $(srctree) $(RCS_FIND_IGNORE) \ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -size 0 \ + -o -name '.*.rej' \ -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ -type f -print | xargs rm -f From 674bfa485554156aa90ce17288712fcb568a42c3 Mon Sep 17 00:00:00 2001 From: Suzuki Poulose Date: Mon, 18 Jul 2011 03:29:20 +0000 Subject: [PATCH 0020/1596] powerpc/44x: Kexec support for PPC440X chipsets This patch adds kexec support for PPC440 based chipsets. This work is based on the KEXEC patches for FSL BookE. The FSL BookE patch and the code flow could be found at the link below: http://patchwork.ozlabs.org/patch/49359/ Steps: 1) Invalidate all the TLB entries except the one this code is run from 2) Create a tmp mapping for our code in the other address space and jump to it 3) Invalidate the entry we used 4) Create a 1:1 mapping for 0-2GiB in blocks of 256M 5) Jump to the new 1:1 mapping and invalidate the tmp mapping I have tested this patches on Ebony, Sequoia boards and Virtex on QEMU. You need kexec-tools commit e8b7939b1e or newer for ppc440x support, available at: git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git Signed-off-by: Suzuki Poulose Cc: Sebastian Andrzej Siewior Signed-off-by: Josh Boyer --- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/kexec.h | 2 +- arch/powerpc/kernel/misc_32.S | 171 +++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 6926b61acfea..0a3d5560c9be 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -345,7 +345,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE config KEXEC bool "kexec system call (EXPERIMENTAL)" - depends on (PPC_BOOK3S || FSL_BOOKE) && EXPERIMENTAL + depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !47x)) && EXPERIMENTAL help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index 8a33698c61bd..f921eb121d39 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -2,7 +2,7 @@ #define _ASM_POWERPC_KEXEC_H #ifdef __KERNEL__ -#ifdef CONFIG_FSL_BOOKE +#if defined(CONFIG_FSL_BOOKE) || defined(CONFIG_44x) /* * On FSL-BookE we setup a 1:1 mapping which covers the first 2GiB of memory diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 998a10028608..f7d760ab5ca1 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -8,6 +8,8 @@ * kexec bits: * Copyright (C) 2002-2003 Eric Biederman * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz + * PPC44x port. Copyright (C) 2011, IBM Corporation + * Author: Suzuki Poulose * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -735,6 +737,175 @@ relocate_new_kernel: mr r4, r30 mr r5, r31 + li r0, 0 +#elif defined(CONFIG_44x) && !defined(CONFIG_47x) + +/* + * Code for setting up 1:1 mapping for PPC440x for KEXEC + * + * We cannot switch off the MMU on PPC44x. + * So we: + * 1) Invalidate all the mappings except the one we are running from. + * 2) Create a tmp mapping for our code in the other address space(TS) and + * jump to it. Invalidate the entry we started in. + * 3) Create a 1:1 mapping for 0-2GiB in chunks of 256M in original TS. + * 4) Jump to the 1:1 mapping in original TS. + * 5) Invalidate the tmp mapping. + * + * - Based on the kexec support code for FSL BookE + * - Doesn't support 47x yet. + * + */ + /* Save our parameters */ + mr r29, r3 + mr r30, r4 + mr r31, r5 + + /* Load our MSR_IS and TID to MMUCR for TLB search */ + mfspr r3,SPRN_PID + mfmsr r4 + andi. r4,r4,MSR_IS@l + beq wmmucr + oris r3,r3,PPC44x_MMUCR_STS@h +wmmucr: + mtspr SPRN_MMUCR,r3 + sync + + /* + * Invalidate all the TLB entries except the current entry + * where we are running from + */ + bl 0f /* Find our address */ +0: mflr r5 /* Make it accessible */ + tlbsx r23,0,r5 /* Find entry we are in */ + li r4,0 /* Start at TLB entry 0 */ + li r3,0 /* Set PAGEID inval value */ +1: cmpw r23,r4 /* Is this our entry? */ + beq skip /* If so, skip the inval */ + tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ +skip: + addi r4,r4,1 /* Increment */ + cmpwi r4,64 /* Are we done? */ + bne 1b /* If not, repeat */ + isync + + /* Create a temp mapping and jump to it */ + andi. r6, r23, 1 /* Find the index to use */ + addi r24, r6, 1 /* r24 will contain 1 or 2 */ + + mfmsr r9 /* get the MSR */ + rlwinm r5, r9, 27, 31, 31 /* Extract the MSR[IS] */ + xori r7, r5, 1 /* Use the other address space */ + + /* Read the current mapping entries */ + tlbre r3, r23, PPC44x_TLB_PAGEID + tlbre r4, r23, PPC44x_TLB_XLAT + tlbre r5, r23, PPC44x_TLB_ATTRIB + + /* Save our current XLAT entry */ + mr r25, r4 + + /* Extract the TLB PageSize */ + li r10, 1 /* r10 will hold PageSize */ + rlwinm r11, r3, 0, 24, 27 /* bits 24-27 */ + + /* XXX: As of now we use 256M, 4K pages */ + cmpwi r11, PPC44x_TLB_256M + bne tlb_4k + rotlwi r10, r10, 28 /* r10 = 256M */ + b write_out +tlb_4k: + cmpwi r11, PPC44x_TLB_4K + bne default + rotlwi r10, r10, 12 /* r10 = 4K */ + b write_out +default: + rotlwi r10, r10, 10 /* r10 = 1K */ + +write_out: + /* + * Write out the tmp 1:1 mapping for this code in other address space + * Fixup EPN = RPN , TS=other address space + */ + insrwi r3, r7, 1, 23 /* Bit 23 is TS for PAGEID field */ + + /* Write out the tmp mapping entries */ + tlbwe r3, r24, PPC44x_TLB_PAGEID + tlbwe r4, r24, PPC44x_TLB_XLAT + tlbwe r5, r24, PPC44x_TLB_ATTRIB + + subi r11, r10, 1 /* PageOffset Mask = PageSize - 1 */ + not r10, r11 /* Mask for PageNum */ + + /* Switch to other address space in MSR */ + insrwi r9, r7, 1, 26 /* Set MSR[IS] = r7 */ + + bl 1f +1: mflr r8 + addi r8, r8, (2f-1b) /* Find the target offset */ + + /* Jump to the tmp mapping */ + mtspr SPRN_SRR0, r8 + mtspr SPRN_SRR1, r9 + rfi + +2: + /* Invalidate the entry we were executing from */ + li r3, 0 + tlbwe r3, r23, PPC44x_TLB_PAGEID + + /* attribute fields. rwx for SUPERVISOR mode */ + li r5, 0 + ori r5, r5, (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) + + /* Create 1:1 mapping in 256M pages */ + xori r7, r7, 1 /* Revert back to Original TS */ + + li r8, 0 /* PageNumber */ + li r6, 3 /* TLB Index, start at 3 */ + +next_tlb: + rotlwi r3, r8, 28 /* Create EPN (bits 0-3) */ + mr r4, r3 /* RPN = EPN */ + ori r3, r3, (PPC44x_TLB_VALID | PPC44x_TLB_256M) /* SIZE = 256M, Valid */ + insrwi r3, r7, 1, 23 /* Set TS from r7 */ + + tlbwe r3, r6, PPC44x_TLB_PAGEID /* PageID field : EPN, V, SIZE */ + tlbwe r4, r6, PPC44x_TLB_XLAT /* Address translation : RPN */ + tlbwe r5, r6, PPC44x_TLB_ATTRIB /* Attributes */ + + addi r8, r8, 1 /* Increment PN */ + addi r6, r6, 1 /* Increment TLB Index */ + cmpwi r8, 8 /* Are we done ? */ + bne next_tlb + isync + + /* Jump to the new mapping 1:1 */ + li r9,0 + insrwi r9, r7, 1, 26 /* Set MSR[IS] = r7 */ + + bl 1f +1: mflr r8 + and r8, r8, r11 /* Get our offset within page */ + addi r8, r8, (2f-1b) + + and r5, r25, r10 /* Get our target PageNum */ + or r8, r8, r5 /* Target jump address */ + + mtspr SPRN_SRR0, r8 + mtspr SPRN_SRR1, r9 + rfi +2: + /* Invalidate the tmp entry we used */ + li r3, 0 + tlbwe r3, r24, PPC44x_TLB_PAGEID + sync + + /* Restore the parameters */ + mr r3, r29 + mr r4, r30 + mr r5, r31 + li r0, 0 #else li r0, 0 From 2f6bab96ef60dd87e0a17272f9f8a6ee12118d32 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 18 Jul 2011 03:49:14 +0000 Subject: [PATCH 0021/1596] powerpc/44x: Add NOR flash device to Yosemite dts Signed-off-by: Stefan Roese Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/yosemite.dts | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/powerpc/boot/dts/yosemite.dts b/arch/powerpc/boot/dts/yosemite.dts index 64923245f0e5..30bb4753577a 100644 --- a/arch/powerpc/boot/dts/yosemite.dts +++ b/arch/powerpc/boot/dts/yosemite.dts @@ -138,6 +138,42 @@ clock-frequency = <0>; /* Filled in by zImage */ interrupts = <0x5 0x1>; interrupt-parent = <&UIC1>; + + nor_flash@0,0 { + compatible = "amd,s29gl256n", "cfi-flash"; + bank-width = <2>; + reg = <0x00000000 0x00000000 0x04000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "kernel"; + reg = <0x00000000 0x001e0000>; + }; + partition@1e0000 { + label = "dtb"; + reg = <0x001e0000 0x00020000>; + }; + partition@200000 { + label = "ramdisk"; + reg = <0x00200000 0x01400000>; + }; + partition@1600000 { + label = "jffs2"; + reg = <0x01600000 0x00400000>; + }; + partition@1a00000 { + label = "user"; + reg = <0x01a00000 0x02540000>; + }; + partition@3f40000 { + label = "env"; + reg = <0x03f40000 0x00040000>; + }; + partition@3f80000 { + label = "u-boot"; + reg = <0x03f80000 0x00080000>; + }; + }; }; UART0: serial@ef600300 { From e7fa1d131472b1134d33aba56a83f8f7689f54fd Mon Sep 17 00:00:00 2001 From: Ayman El-Khashab Date: Wed, 20 Jul 2011 03:02:29 +0000 Subject: [PATCH 0022/1596] powerpc/4xx: enable and fix pcie gen1/gen2 on the 460sx Adds a register to the config space for the 460sx. Changes the vc0 detect to a pll detect. maps configuration space to test the link status. changes the setup to enable gen2 devices to operate at gen2 speeds. fixes mapping that was not correct for the 460sx. added bit definitions for the OMRxMSKL registers. Removed reserved bit that was set incorrectly in the OMR2MSKL register. tested on the 460sx eiger and custom board Signed-off-by: Ayman El-Khashab Signed-off-by: Josh Boyer --- arch/powerpc/sysdev/ppc4xx_pci.c | 89 ++++++++++++++++++++++++++------ arch/powerpc/sysdev/ppc4xx_pci.h | 12 +++++ 2 files changed, 84 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index a59ba96d2c21..edd51c85835a 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -1091,6 +1091,10 @@ static int __init ppc460sx_pciex_core_init(struct device_node *np) mtdcri(SDR0, PESDR1_460SX_HSSSLEW, 0xFFFF0000); mtdcri(SDR0, PESDR2_460SX_HSSSLEW, 0xFFFF0000); + /* Set HSS PRBS enabled */ + mtdcri(SDR0, PESDR0_460SX_HSSCTLSET, 0x00001130); + mtdcri(SDR0, PESDR2_460SX_HSSCTLSET, 0x00001130); + udelay(100); /* De-assert PLLRESET */ @@ -1131,9 +1135,6 @@ static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2, 0, 0x01000000); - /*Gen-1*/ - mtdcri(SDR0, port->sdr_base + PESDRn_460SX_RCEI, 0x08000000); - dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL), PESDRx_RCSSET_RSTPYN); @@ -1147,14 +1148,42 @@ static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) { /* Max 128 Bytes */ out_be32 (port->utl_base + PEUTL_PBBSZ, 0x00000000); + /* Assert VRB and TXE - per datasheet turn off addr validation */ + out_be32(port->utl_base + PEUTL_PCTL, 0x80800000); return 0; } +static void __init ppc460sx_pciex_check_link(struct ppc4xx_pciex_port *port) +{ + void __iomem *mbase; + int attempt = 50; + + port->link = 0; + + mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); + if (mbase == NULL) { + printk(KERN_ERR "%s: Can't map internal config space !", + port->node->full_name); + goto done; + } + + while (attempt && (0 == (in_le32(mbase + PECFG_460SX_DLLSTA) + & PECFG_460SX_DLLSTA_LINKUP))) { + attempt--; + mdelay(10); + } + if (attempt) + port->link = 1; +done: + iounmap(mbase); + +} + static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = { .core_init = ppc460sx_pciex_core_init, .port_init_hw = ppc460sx_pciex_init_port_hw, .setup_utl = ppc460sx_pciex_init_utl, - .check_link = ppc4xx_pciex_check_link_sdr, + .check_link = ppc460sx_pciex_check_link, }; #endif /* CONFIG_44x */ @@ -1337,15 +1366,15 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) if (rc != 0) return rc; - if (ppc4xx_pciex_hwops->check_link) - ppc4xx_pciex_hwops->check_link(port); - /* * Initialize mapping: disable all regions and configure * CFG and REG regions based on resources in the device tree */ ppc4xx_pciex_port_init_mapping(port); + if (ppc4xx_pciex_hwops->check_link) + ppc4xx_pciex_hwops->check_link(port); + /* * Map UTL */ @@ -1359,13 +1388,23 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) ppc4xx_pciex_hwops->setup_utl(port); /* - * Check for VC0 active and assert RDY. + * Check for VC0 active or PLL Locked and assert RDY. */ if (port->sdr_base) { - if (port->link && - ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, - 1 << 16, 1 << 16, 5000)) { - printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); + if (of_device_is_compatible(port->node, + "ibm,plb-pciex-460sx")){ + if (port->link && ppc4xx_pciex_wait_on_sdr(port, + PESDRn_RCSSTS, + 1 << 12, 1 << 12, 5000)) { + printk(KERN_INFO "PCIE%d: PLL not locked\n", + port->index); + port->link = 0; + } + } else if (port->link && + ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, + 1 << 16, 1 << 16, 5000)) { + printk(KERN_INFO "PCIE%d: VC0 not active\n", + port->index); port->link = 0; } @@ -1572,8 +1611,15 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); - /* Note that 3 here means enabled | single region */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); + /*Enabled and single region */ + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, + sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT + | DCRO_PEGPL_OMRxMSKL_VAL); + else + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, + sa | DCRO_PEGPL_OMR1MSKL_UOT + | DCRO_PEGPL_OMRxMSKL_VAL); break; case 1: out_le32(mbase + PECFG_POM1LAH, pciah); @@ -1581,8 +1627,8 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); - /* Note that 3 here means enabled | single region */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, + sa | DCRO_PEGPL_OMRxMSKL_VAL); break; case 2: out_le32(mbase + PECFG_POM2LAH, pciah); @@ -1591,7 +1637,9 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); /* Note that 3 here means enabled | IO space !!! */ - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, + sa | DCRO_PEGPL_OMR3MSKL_IO + | DCRO_PEGPL_OMRxMSKL_VAL); break; } @@ -1692,6 +1740,9 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, if (res->flags & IORESOURCE_PREFETCH) sa |= 0x8; + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + sa |= PCI_BASE_ADDRESS_MEM_TYPE_64; + out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); @@ -1853,6 +1904,10 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) } out_le16(mbase + 0x202, val); + /* Enable Bus master, memory, and io space */ + if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx")) + out_le16(mbase + 0x204, 0x7); + if (!port->endpoint) { /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ out_le32(mbase + 0x208, 0x06040001); diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h index c39a134e8684..32ce763a375a 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.h +++ b/arch/powerpc/sysdev/ppc4xx_pci.h @@ -464,6 +464,18 @@ #define PECFG_POM2LAL 0x390 #define PECFG_POM2LAH 0x394 +/* 460sx only */ +#define PECFG_460SX_DLLSTA 0x3f8 + +/* 460sx Bit Mappings */ +#define PECFG_460SX_DLLSTA_LINKUP 0x00000010 +#define DCRO_PEGPL_460SX_OMR1MSKL_UOT 0x00000004 + +/* PEGPL Bit Mappings */ +#define DCRO_PEGPL_OMRxMSKL_VAL 0x00000001 +#define DCRO_PEGPL_OMR1MSKL_UOT 0x00000002 +#define DCRO_PEGPL_OMR3MSKL_IO 0x00000002 + /* SDR Bit Mappings */ #define PESDRx_RCSSET_HLDPLB 0x10000000 #define PESDRx_RCSSET_RSTGU 0x01000000 From e57b708beaf1bc14031cb9749b574c9aa1f6188f Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Thu, 7 Jul 2011 06:09:58 +0000 Subject: [PATCH 0023/1596] powerpc/4xx: edac: Add comma to fix build error Commit 4018294b53d1dae026880e45f174c1cc63b5d435 broke the ppc4xx_edac driver at line 210 where the struct member is missing a comma. Signed-off-by: Mike Williams Signed-off-by: Josh Boyer --- drivers/edac/ppc4xx_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 0de7d8770891..38400963e245 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -205,7 +205,7 @@ static struct platform_driver ppc4xx_edac_driver = { .remove = ppc4xx_edac_remove, .driver = { .owner = THIS_MODULE, - .name = PPC4XX_EDAC_MODULE_NAME + .name = PPC4XX_EDAC_MODULE_NAME, .of_match_table = ppc4xx_edac_match, }, }; From 9fcd768d0cc88b41ea459e25d2db12d3e25fa9dd Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 11 Aug 2011 13:53:44 -0400 Subject: [PATCH 0024/1596] powerpc/40x: Remove obsolete HCU4 board The HCU4 board is unmaintained. Remove it. Signed-off-by: Niklaus Giger Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/hcu4.dts | 168 ------------------------ arch/powerpc/configs/40x/hcu4_defconfig | 80 ----------- arch/powerpc/configs/ppc40x_defconfig | 1 - arch/powerpc/platforms/40x/Kconfig | 8 -- arch/powerpc/platforms/40x/Makefile | 1 - arch/powerpc/platforms/40x/hcu4.c | 61 --------- 6 files changed, 319 deletions(-) delete mode 100644 arch/powerpc/boot/dts/hcu4.dts delete mode 100644 arch/powerpc/configs/40x/hcu4_defconfig delete mode 100644 arch/powerpc/platforms/40x/hcu4.c diff --git a/arch/powerpc/boot/dts/hcu4.dts b/arch/powerpc/boot/dts/hcu4.dts deleted file mode 100644 index 7988598da4c9..000000000000 --- a/arch/powerpc/boot/dts/hcu4.dts +++ /dev/null @@ -1,168 +0,0 @@ -/* -* Device Tree Source for Netstal Maschinen HCU4 -* based on the IBM Walnut -* -* Copyright 2008 -* Niklaus Giger -* -* Copyright 2007 IBM Corp. -* Josh Boyer -* -* This file is licensed under the terms of the GNU General Public -* License version 2. This program is licensed "as is" without -* any warranty of any kind, whether express or implied. -*/ - -/dts-v1/; - -/ { - #address-cells = <0x1>; - #size-cells = <0x1>; - model = "netstal,hcu4"; - compatible = "netstal,hcu4"; - dcr-parent = <0x1>; - - aliases { - ethernet0 = "/plb/opb/ethernet@ef600800"; - serial0 = "/plb/opb/serial@ef600300"; - }; - - cpus { - #address-cells = <0x1>; - #size-cells = <0x0>; - - cpu@0 { - device_type = "cpu"; - model = "PowerPC,405GPr"; - reg = <0x0>; - clock-frequency = <0>; /* Filled in by U-Boot */ - timebase-frequency = <0x0>; /* Filled in by U-Boot */ - i-cache-line-size = <0x20>; - d-cache-line-size = <0x20>; - i-cache-size = <0x4000>; - d-cache-size = <0x4000>; - dcr-controller; - dcr-access-method = "native"; - linux,phandle = <0x1>; - }; - }; - - memory { - device_type = "memory"; - reg = <0x0 0x0>; /* Filled in by U-Boot */ - }; - - UIC0: interrupt-controller { - compatible = "ibm,uic"; - interrupt-controller; - cell-index = <0x0>; - dcr-reg = <0xc0 0x9>; - #address-cells = <0x0>; - #size-cells = <0x0>; - #interrupt-cells = <0x2>; - linux,phandle = <0x2>; - }; - - plb { - compatible = "ibm,plb3"; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges; - clock-frequency = <0x0>; /* Filled in by U-Boot */ - - SDRAM0: memory-controller { - compatible = "ibm,sdram-405gp"; - dcr-reg = <0x10 0x2>; - }; - - MAL: mcmal { - compatible = "ibm,mcmal-405gp", "ibm,mcmal"; - dcr-reg = <0x180 0x62>; - num-tx-chans = <0x1>; - num-rx-chans = <0x1>; - interrupt-parent = <0x2>; - interrupts = <0xb 0x4 0xc 0x4 0xa 0x4 0xd 0x4 0xe 0x4>; - linux,phandle = <0x3>; - }; - - POB0: opb { - compatible = "ibm,opb-405gp", "ibm,opb"; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges = <0xef600000 0xef600000 0xa00000>; - dcr-reg = <0xa0 0x5>; - clock-frequency = <0x0>; /* Filled in by U-Boot */ - - UART0: serial@ef600300 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600300 0x8>; - virtual-reg = <0xef600300>; - clock-frequency = <0x0>;/* Filled in by U-Boot */ - current-speed = <0>; /* Filled in by U-Boot */ - interrupt-parent = <0x2>; - interrupts = <0x0 0x4>; - }; - - IIC: i2c@ef600500 { - compatible = "ibm,iic-405gp", "ibm,iic"; - reg = <0xef600500 0x11>; - interrupt-parent = <0x2>; - interrupts = <0x2 0x4>; - }; - - GPIO: gpio@ef600700 { - compatible = "ibm,gpio-405gp"; - reg = <0xef600700 0x20>; - }; - - EMAC: ethernet@ef600800 { - device_type = "network"; - compatible = "ibm,emac-405gp", "ibm,emac"; - interrupt-parent = <0x2>; - interrupts = <0xf 0x4 0x9 0x4>; - local-mac-address = [00 00 00 00 00 00]; - reg = <0xef600800 0x70>; - mal-device = <0x3>; - mal-tx-channel = <0x0>; - mal-rx-channel = <0x0>; - cell-index = <0x0>; - max-frame-size = <0x5dc>; - rx-fifo-size = <0x1000>; - tx-fifo-size = <0x800>; - phy-mode = "rmii"; - phy-map = <0x1>; - }; - }; - - EBC0: ebc { - compatible = "ibm,ebc-405gp", "ibm,ebc"; - dcr-reg = <0x12 0x2>; - #address-cells = <0x2>; - #size-cells = <0x1>; - clock-frequency = <0x0>; /* Filled in by U-Boot */ - - sram@0,0 { - reg = <0x0 0x0 0x80000>; - }; - - flash@0,80000 { - compatible = "jedec-flash"; - bank-width = <0x1>; - reg = <0x0 0x80000 0x80000>; - #address-cells = <0x1>; - #size-cells = <0x1>; - - partition@0 { - label = "OpenBIOS"; - reg = <0x0 0x80000>; - read-only; - }; - }; - }; - }; - - chosen { - linux,stdout-path = "/plb/opb/serial@ef600300"; - }; -}; diff --git a/arch/powerpc/configs/40x/hcu4_defconfig b/arch/powerpc/configs/40x/hcu4_defconfig deleted file mode 100644 index ebeb4accad65..000000000000 --- a/arch/powerpc/configs/40x/hcu4_defconfig +++ /dev/null @@ -1,80 +0,0 @@ -CONFIG_40x=y -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_HCU4=y -# CONFIG_WALNUT is not set -CONFIG_SPARSE_IRQ=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -# CONFIG_IPV6 is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_CONNECTOR=y -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=m -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=35000 -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_IBM_NEW_EMAC=y -# CONFIG_INPUT is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m -# CONFIG_USB_SUPPORT is not set -CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/ppc40x_defconfig b/arch/powerpc/configs/ppc40x_defconfig index bfd634b5ada7..e9d920c5a87a 100644 --- a/arch/powerpc/configs/ppc40x_defconfig +++ b/arch/powerpc/configs/ppc40x_defconfig @@ -14,7 +14,6 @@ CONFIG_MODULE_UNLOAD=y CONFIG_PPC4xx_GPIO=y CONFIG_ACADIA=y CONFIG_EP405=y -CONFIG_HCU4=y CONFIG_HOTFOOT=y CONFIG_KILAUEA=y CONFIG_MAKALU=y diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index d733d7ca939c..ae5e0bfc0234 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -32,14 +32,6 @@ config EP405 help This option enables support for the EP405/EP405PC boards. -config HCU4 - bool "Hcu4" - depends on 40x - default n - select 405GPR - help - This option enables support for the Nestal Maschinen HCU4 board. - config HOTFOOT bool "Hotfoot" depends on 40x diff --git a/arch/powerpc/platforms/40x/Makefile b/arch/powerpc/platforms/40x/Makefile index 56e89004c468..88c22de0c850 100644 --- a/arch/powerpc/platforms/40x/Makefile +++ b/arch/powerpc/platforms/40x/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_HCU4) += hcu4.o obj-$(CONFIG_WALNUT) += walnut.o obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o obj-$(CONFIG_EP405) += ep405.o diff --git a/arch/powerpc/platforms/40x/hcu4.c b/arch/powerpc/platforms/40x/hcu4.c deleted file mode 100644 index 60b2afecab75..000000000000 --- a/arch/powerpc/platforms/40x/hcu4.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Architecture- / platform-specific boot-time initialization code for - * IBM PowerPC 4xx based boards. Adapted from original - * code by Gary Thomas, Cort Dougan , and Dan Malek - * . - * - * Copyright(c) 1999-2000 Grant Erickson - * - * Rewritten and ported to the merged powerpc tree: - * Copyright 2007 IBM Corporation - * Josh Boyer - * - * 2002 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -static __initdata struct of_device_id hcu4_of_bus[] = { - { .compatible = "ibm,plb3", }, - { .compatible = "ibm,opb", }, - { .compatible = "ibm,ebc", }, - {}, -}; - -static int __init hcu4_device_probe(void) -{ - of_platform_bus_probe(NULL, hcu4_of_bus, NULL); - return 0; -} -machine_device_initcall(hcu4, hcu4_device_probe); - -static int __init hcu4_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - if (!of_flat_dt_is_compatible(root, "netstal,hcu4")) - return 0; - - return 1; -} - -define_machine(hcu4) { - .name = "HCU4", - .probe = hcu4_probe, - .progress = udbg_progress, - .init_IRQ = uic_init_tree, - .get_irq = uic_get_irq, - .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, -}; From 1712cde28532d9b0c98142e08a131b344d3200bd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 28 May 2011 10:36:29 -0700 Subject: [PATCH 0025/1596] mtd: convert vmalloc/memset to vzalloc Signed-off-by: Joe Perches Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdswap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index fd7885327611..5e5423b2aed2 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1374,11 +1374,10 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, goto revmap_fail; eblk_bytes = sizeof(struct swap_eb)*d->eblks; - d->eb_data = vmalloc(eblk_bytes); + d->eb_data = vzalloc(eblk_bytes); if (!d->eb_data) goto eb_data_fail; - memset(d->eb_data, 0, eblk_bytes); for (i = 0; i < pages; i++) d->page_data[i] = BLOCK_UNDEF; From 1c3bd14bb0e10ce69761662d575d454f12070838 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 31 May 2011 21:20:53 +0800 Subject: [PATCH 0026/1596] mtd: onenand: return proper error if regulator_get fails Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/omap2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index a916dec29215..0d9073d4e417 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -741,6 +741,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) c->regulator = regulator_get(&pdev->dev, "vonenand"); if (IS_ERR(c->regulator)) { dev_err(&pdev->dev, "Failed to get regulator\n"); + r = PTR_ERR(c->regulator); goto err_release_dma; } c->onenand.enable = omap2_onenand_enable; From a16e470caa173d323ef68dcac98c899b95fa4f84 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 9 Aug 2011 10:08:10 +0530 Subject: [PATCH 0027/1596] dmaengine: remove struct scatterlist for header Commit 90b44f8 introduces dmaengine_prep_slave_single API which adds scatterlist.h in dmaengine.h, so defining struct scatterlist is not required Signed-off-by: Vinod Koul Acked-by: Dan Williams --- include/linux/dmaengine.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 0d738c95fe4e..ace51af4369f 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -26,8 +26,6 @@ #include #include -struct scatterlist; - /** * typedef dma_cookie_t - an opaque DMA cookie * From ef298c21c0d9c06ed89ea2fa724c3a018acfff39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Mon, 8 Aug 2011 14:47:47 +0200 Subject: [PATCH 0028/1596] mxs-dma: enable CLKGATE before accessing registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After calling mxs_dma_disable_chan() for a channel, that channel becomes unusable because some controller registers can only be written when the clock is enabled via CLKGATE. Signed-off-by: Lothar Waßmann Signed-off-by: Vinod Koul --- drivers/dma/mxs-dma.c | 45 +++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index be641cbd36fc..b4588bdd98bb 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -130,6 +130,23 @@ struct mxs_dma_engine { struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; }; +static inline void mxs_dma_clkgate(struct mxs_dma_chan *mxs_chan, int enable) +{ + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int chan_id = mxs_chan->chan.chan_id; + int set_clr = enable ? MXS_CLR_ADDR : MXS_SET_ADDR; + + /* enable apbh channel clock */ + if (dma_is_apbh()) { + if (apbh_is_old()) + writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), + mxs_dma->base + HW_APBHX_CTRL0 + set_clr); + else + writel(1 << chan_id, + mxs_dma->base + HW_APBHX_CTRL0 + set_clr); + } +} + static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan) { struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; @@ -148,38 +165,21 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan) struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; int chan_id = mxs_chan->chan.chan_id; + /* clkgate needs to be enabled before writing other registers */ + mxs_dma_clkgate(mxs_chan, 1); + /* set cmd_addr up */ writel(mxs_chan->ccw_phys, mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id)); - /* enable apbh channel clock */ - if (dma_is_apbh()) { - if (apbh_is_old()) - writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), - mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); - else - writel(1 << chan_id, - mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); - } - /* write 1 to SEMA to kick off the channel */ writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id)); } static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan) { - struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; - int chan_id = mxs_chan->chan.chan_id; - /* disable apbh channel clock */ - if (dma_is_apbh()) { - if (apbh_is_old()) - writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), - mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); - else - writel(1 << chan_id, - mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); - } + mxs_dma_clkgate(mxs_chan, 0); mxs_chan->status = DMA_SUCCESS; } @@ -338,7 +338,10 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan) if (ret) goto err_clk; + /* clkgate needs to be enabled for reset to finish */ + mxs_dma_clkgate(mxs_chan, 1); mxs_dma_reset_chan(mxs_chan); + mxs_dma_clkgate(mxs_chan, 0); dma_async_tx_descriptor_init(&mxs_chan->desc, chan); mxs_chan->desc.tx_submit = mxs_dma_tx_submit; From 2c929420e8b532c14688dcd500253b90a24e7233 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 18 Aug 2011 19:24:54 +0900 Subject: [PATCH 0029/1596] ARM: EXYNOS4: use dma-pl330 device name for clock This change replaces s3c-pl330.x clock device names with dma-pl330.x, otherwise there won't be a correspondence between clock device name and amba device name, thus clocks can't be enabled. Fixes runtime errors on clk_get() from drivers/dma/pl330.c: dma-pl330 dma-pl330.0: Cannot get operation clock. dma-pl330: probe of dma-pl330.0 failed with error -22 Signed-off-by: Vladimir Zapolskiy Acked-by: Boojin Kim Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c index 851dea018578..c7b622587229 100644 --- a/arch/arm/mach-exynos4/clock.c +++ b/arch/arm/mach-exynos4/clock.c @@ -455,12 +455,12 @@ static struct clk init_clocks_off[] = { .ctrlbit = (1 << 10), }, { .name = "pdma", - .devname = "s3c-pl330.0", + .devname = "dma-pl330.0", .enable = exynos4_clk_ip_fsys_ctrl, .ctrlbit = (1 << 0), }, { .name = "pdma", - .devname = "s3c-pl330.1", + .devname = "dma-pl330.1", .enable = exynos4_clk_ip_fsys_ctrl, .ctrlbit = (1 << 1), }, { From d20cc4c1b660d59a25f8bebef5d55c1872b9aa76 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 18 Aug 2011 19:24:55 +0900 Subject: [PATCH 0030/1596] ARM: S5PC100: use dma-pl330 device name for clock This change replaces s3c-pl330.x clock device names with dma-pl330.x, otherwise there won't be a correspondence between clock device name and amba device name, thus clocks can't be enabled. Fixes runtime errors on clk_get() from drivers/dma/pl330.c: dma-pl330 dma-pl330.0: Cannot get operation clock. dma-pl330: probe of dma-pl330.0 failed with error -22 Signed-off-by: Vladimir Zapolskiy Acked-by: Boojin Kim Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pc100/clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c index ff5cbb30de5b..1f69f342a0a0 100644 --- a/arch/arm/mach-s5pc100/clock.c +++ b/arch/arm/mach-s5pc100/clock.c @@ -455,13 +455,13 @@ static struct clk init_clocks_off[] = { .ctrlbit = (1 << 2), }, { .name = "pdma", - .devname = "s3c-pl330.1", + .devname = "dma-pl330.1", .parent = &clk_div_d1_bus.clk, .enable = s5pc100_d1_0_ctrl, .ctrlbit = (1 << 1), }, { .name = "pdma", - .devname = "s3c-pl330.0", + .devname = "dma-pl330.0", .parent = &clk_div_d1_bus.clk, .enable = s5pc100_d1_0_ctrl, .ctrlbit = (1 << 0), From 1ce3ea61c61c1e2127496df2c5d66650fd6456e2 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 18 Aug 2011 19:24:55 +0900 Subject: [PATCH 0031/1596] ARM: S5PV210: use dma-pl330 device name for clock This change replaces s3c-pl330.x clock device names with dma-pl330.x, otherwise there won't be a correspondence between clock device name and amba device name, thus clocks can't be enabled. Fixes runtime errors on clk_get() from drivers/dma/pl330.c: dma-pl330 dma-pl330.0: Cannot get operation clock. dma-pl330: probe of dma-pl330.0 failed with error -22 Signed-off-by: Vladimir Zapolskiy Acked-by: Boojin Kim Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv210/clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c index 52a8e607bcc2..50d458047c09 100644 --- a/arch/arm/mach-s5pv210/clock.c +++ b/arch/arm/mach-s5pv210/clock.c @@ -290,13 +290,13 @@ static struct clk_ops clk_fout_apll_ops = { static struct clk init_clocks_off[] = { { .name = "pdma", - .devname = "s3c-pl330.0", + .devname = "dma-pl330.0", .parent = &clk_hclk_psys.clk, .enable = s5pv210_clk_ip0_ctrl, .ctrlbit = (1 << 3), }, { .name = "pdma", - .devname = "s3c-pl330.1", + .devname = "dma-pl330.1", .parent = &clk_hclk_psys.clk, .enable = s5pv210_clk_ip0_ctrl, .ctrlbit = (1 << 4), From 2213d0c0bae510df3860a48e107a5ba17ac72e99 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Thu, 18 Aug 2011 19:24:55 +0900 Subject: [PATCH 0032/1596] ARM: S5P64X0: Add the devname for DMA clock This patch adds devname for DMA clock. NOTE: This patch should be added after merging new pl330 driver on dmaengine. Signed-off-by: Boojin Kim Signed-off-by: Kukjin Kim --- arch/arm/mach-s5p64x0/clock-s5p6440.c | 1 + arch/arm/mach-s5p64x0/clock-s5p6450.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c index 0e9cd3092dd2..fd7b08fd262b 100644 --- a/arch/arm/mach-s5p64x0/clock-s5p6440.c +++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c @@ -147,6 +147,7 @@ static struct clk init_clocks_off[] = { .ctrlbit = (1 << 8), }, { .name = "pdma", + .devname = "dma-pl330", .parent = &clk_hclk_low.clk, .enable = s5p64x0_hclk0_ctrl, .ctrlbit = (1 << 12), diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c index d9dc16cde109..1d989b8da039 100644 --- a/arch/arm/mach-s5p64x0/clock-s5p6450.c +++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c @@ -180,6 +180,7 @@ static struct clk init_clocks_off[] = { .ctrlbit = (1 << 3), }, { .name = "pdma", + .devname = "dma-pl330", .parent = &clk_hclk_low.clk, .enable = s5p64x0_hclk0_ctrl, .ctrlbit = (1 << 12), From 25ac0c2b971235d3e8c7af0b6889a1eb6988b559 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 19 Aug 2011 14:48:17 +0200 Subject: [PATCH 0033/1596] nbd: use task_pid_nr() to get current pid Signed-off-by: WANG Cong Cc: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index f533f3375e24..a928287177fd 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -405,7 +405,7 @@ static int nbd_do_it(struct nbd_device *lo) BUG_ON(lo->magic != LO_MAGIC); - lo->pid = current->pid; + lo->pid = task_pid_nr(current); ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr); if (ret) { printk(KERN_ERR "nbd: sysfs_create_file failed!"); From 1695b87f7dd152b866f0dd867c8e599025fc4965 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 19 Aug 2011 14:48:21 +0200 Subject: [PATCH 0034/1596] nbd: replace sysfs_create_file() with device_create_file() Signed-off-by: WANG Cong Cc: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index a928287177fd..da98360b6463 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -406,9 +406,9 @@ static int nbd_do_it(struct nbd_device *lo) BUG_ON(lo->magic != LO_MAGIC); lo->pid = task_pid_nr(current); - ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr); + ret = device_create_file(disk_to_dev(lo->disk), &pid_attr); if (ret) { - printk(KERN_ERR "nbd: sysfs_create_file failed!"); + printk(KERN_ERR "nbd: device_create_file failed!"); lo->pid = 0; return ret; } @@ -416,7 +416,7 @@ static int nbd_do_it(struct nbd_device *lo) while ((req = nbd_read_stat(lo)) != NULL) nbd_end_request(req); - sysfs_remove_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr); + device_remove_file(disk_to_dev(lo->disk), &pid_attr); lo->pid = 0; return 0; } From 7f1b90f99a2d4253f8eb1221d39da072178adbc5 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 19 Aug 2011 14:48:22 +0200 Subject: [PATCH 0035/1596] nbd: replace printk KERN_ERR with dev_err() Signed-off-by: WANG Cong Cc: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index da98360b6463..1b8e09fffd5a 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -158,8 +158,9 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size, sigset_t blocked, oldset; if (unlikely(!sock)) { - printk(KERN_ERR "%s: Attempted %s on closed socket in sock_xmit\n", - lo->disk->disk_name, (send ? "send" : "recv")); + dev_err(disk_to_dev(lo->disk), + "Attempted %s on closed socket in sock_xmit\n", + (send ? "send" : "recv")); return -EINVAL; } @@ -250,8 +251,8 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) result = sock_xmit(lo, 1, &request, sizeof(request), (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0); if (result <= 0) { - printk(KERN_ERR "%s: Send control failed (result %d)\n", - lo->disk->disk_name, result); + dev_err(disk_to_dev(lo->disk), + "Send control failed (result %d)\n", result); goto error_out; } @@ -270,8 +271,9 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) lo->disk->disk_name, req, bvec->bv_len); result = sock_send_bvec(lo, bvec, flags); if (result <= 0) { - printk(KERN_ERR "%s: Send data failed (result %d)\n", - lo->disk->disk_name, result); + dev_err(disk_to_dev(lo->disk), + "Send data failed (result %d)\n", + result); goto error_out; } } @@ -328,14 +330,13 @@ static struct request *nbd_read_stat(struct nbd_device *lo) reply.magic = 0; result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL); if (result <= 0) { - printk(KERN_ERR "%s: Receive control failed (result %d)\n", - lo->disk->disk_name, result); + dev_err(disk_to_dev(lo->disk), + "Receive control failed (result %d)\n", result); goto harderror; } if (ntohl(reply.magic) != NBD_REPLY_MAGIC) { - printk(KERN_ERR "%s: Wrong magic (0x%lx)\n", - lo->disk->disk_name, + dev_err(disk_to_dev(lo->disk), "Wrong magic (0x%lx)\n", (unsigned long)ntohl(reply.magic)); result = -EPROTO; goto harderror; @@ -347,15 +348,15 @@ static struct request *nbd_read_stat(struct nbd_device *lo) if (result != -ENOENT) goto harderror; - printk(KERN_ERR "%s: Unexpected reply (%p)\n", - lo->disk->disk_name, reply.handle); + dev_err(disk_to_dev(lo->disk), "Unexpected reply (%p)\n", + reply.handle); result = -EBADR; goto harderror; } if (ntohl(reply.error)) { - printk(KERN_ERR "%s: Other side returned error (%d)\n", - lo->disk->disk_name, ntohl(reply.error)); + dev_err(disk_to_dev(lo->disk), "Other side returned error (%d)\n", + ntohl(reply.error)); req->errors++; return req; } @@ -369,8 +370,8 @@ static struct request *nbd_read_stat(struct nbd_device *lo) rq_for_each_segment(bvec, req, iter) { result = sock_recv_bvec(lo, bvec); if (result <= 0) { - printk(KERN_ERR "%s: Receive data failed (result %d)\n", - lo->disk->disk_name, result); + dev_err(disk_to_dev(lo->disk), "Receive data failed (result %d)\n", + result); req->errors++; return req; } @@ -408,7 +409,7 @@ static int nbd_do_it(struct nbd_device *lo) lo->pid = task_pid_nr(current); ret = device_create_file(disk_to_dev(lo->disk), &pid_attr); if (ret) { - printk(KERN_ERR "nbd: device_create_file failed!"); + dev_err(disk_to_dev(lo->disk), "device_create_file failed!\n"); lo->pid = 0; return ret; } @@ -457,8 +458,8 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req) if (rq_data_dir(req) == WRITE) { nbd_cmd(req) = NBD_CMD_WRITE; if (lo->flags & NBD_READ_ONLY) { - printk(KERN_ERR "%s: Write on read-only\n", - lo->disk->disk_name); + dev_err(disk_to_dev(lo->disk), + "Write on read-only\n"); goto error_out; } } @@ -468,16 +469,15 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req) mutex_lock(&lo->tx_lock); if (unlikely(!lo->sock)) { mutex_unlock(&lo->tx_lock); - printk(KERN_ERR "%s: Attempted send on closed socket\n", - lo->disk->disk_name); + dev_err(disk_to_dev(lo->disk), + "Attempted send on closed socket\n"); goto error_out; } lo->active_req = req; if (nbd_send_req(lo, req) != 0) { - printk(KERN_ERR "%s: Request send failed\n", - lo->disk->disk_name); + dev_err(disk_to_dev(lo->disk), "Request send failed\n"); req->errors++; nbd_end_request(req); } else { @@ -549,8 +549,8 @@ static void do_nbd_request(struct request_queue *q) BUG_ON(lo->magic != LO_MAGIC); if (unlikely(!lo->sock)) { - printk(KERN_ERR "%s: Attempted send on closed socket\n", - lo->disk->disk_name); + dev_err(disk_to_dev(lo->disk), + "Attempted send on closed socket\n"); req->errors++; nbd_end_request(req); spin_lock_irq(q->queue_lock); From 7742ce4ab49976851ce7f0185dcbe491935371a2 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 19 Aug 2011 14:48:28 +0200 Subject: [PATCH 0036/1596] nbd: lower the loglevel of an error message This is only an error, no need to use KERN_CRIT log level. Signed-off-by: WANG Cong Cc: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 1b8e09fffd5a..2b5fc11be377 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -745,7 +745,7 @@ static int __init nbd_init(void) BUILD_BUG_ON(sizeof(struct nbd_request) != 28); if (max_part < 0) { - printk(KERN_CRIT "nbd: max_part must be >= 0\n"); + printk(KERN_ERR "nbd: max_part must be >= 0\n"); return -EINVAL; } From 5eedf5415cd57f8db8642a5db4cf8e5507390030 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 19 Aug 2011 14:48:28 +0200 Subject: [PATCH 0037/1596] nbd: replace some printk with dev_warn() and dev_info() Signed-off-by: WANG Cong Cc: Paul Clements Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 2b5fc11be377..3353d98f81d6 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -127,8 +127,7 @@ static void sock_shutdown(struct nbd_device *lo, int lock) if (lock) mutex_lock(&lo->tx_lock); if (lo->sock) { - printk(KERN_WARNING "%s: shutting down socket\n", - lo->disk->disk_name); + dev_warn(disk_to_dev(lo->disk), "shutting down socket\n"); kernel_sock_shutdown(lo->sock, SHUT_RDWR); lo->sock = NULL; } @@ -576,7 +575,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, case NBD_DISCONNECT: { struct request sreq; - printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); + dev_info(disk_to_dev(lo->disk), "NBD_DISCONNECT\n"); blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; @@ -674,7 +673,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, file = lo->file; lo->file = NULL; nbd_clear_que(lo); - printk(KERN_WARNING "%s: queue cleared\n", lo->disk->disk_name); + dev_warn(disk_to_dev(lo->disk), "queue cleared\n"); if (file) fput(file); lo->bytesize = 0; @@ -694,8 +693,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, return 0; case NBD_PRINT_DEBUG: - printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", - bdev->bd_disk->disk_name, + dev_info(disk_to_dev(lo->disk), + "next = %p, prev = %p, head = %p\n", lo->queue_head.next, lo->queue_head.prev, &lo->queue_head); return 0; From 548ef6cc26ca1c81f19855d57d3fb0f9a7ce3385 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 19 Aug 2011 14:48:28 +0200 Subject: [PATCH 0038/1596] nbd-replace-some-printk-with-dev_warn-and-dev_info-checkpatch-fixes ERROR: code indent should use tabs where possible #30: FILE: drivers/block/nbd.c:578: +^I dev_info(disk_to_dev(lo->disk), "NBD_DISCONNECT\n");$ total: 1 errors, 0 warnings, 35 lines checked NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or scripts/cleanfile ./patches/nbd-replace-some-printk-with-dev_warn-and-dev_info.patch has style problems, please review. If any of these errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS. Please run checkpatch prior to sending patches Cc: Paul Clements Cc: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 3353d98f81d6..c3f0ee16594d 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -575,7 +575,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, case NBD_DISCONNECT: { struct request sreq; - dev_info(disk_to_dev(lo->disk), "NBD_DISCONNECT\n"); + dev_info(disk_to_dev(lo->disk), "NBD_DISCONNECT\n"); blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; From dfaa2ef68e80c378e610e3c8c536f1c239e8d3ef Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Fri, 19 Aug 2011 14:50:46 +0200 Subject: [PATCH 0039/1596] loop: add discard support for loop devices This commit adds discard support for loop devices. Discard is usually supported by SSD and thinly provisioned devices as a method for reclaiming unused space. This is no different than trying to reclaim back space which is not used by the file system on the image, but it still occupies space on the host file system. We can do the reclamation on file system which does support hole punching. So when discard request gets to the loop driver we can translate that to punch a hole to the underlying file, hence reclaim the free space. This is very useful for trimming down the size of the image to only what is really used by the file system on that image. Fstrim may be used for that purpose. It has been tested on ext4, xfs and btrfs with the image file systems ext4, ext3, xfs and btrfs. ext4, or ext6 image on ext4 file system has some problems but it seems that ext4 punch hole implementation is somewhat flawed and it is unrelated to this commit. Also this is a very good method of validating file systems punch hole implementation. Note that when encryption is used, discard support is disabled, because using it might leak some information useful for possible attacker. Signed-off-by: Lukas Czerner Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe --- drivers/block/loop.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 76c8da78212b..936cac3c3126 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -75,6 +75,7 @@ #include #include #include +#include #include @@ -484,6 +485,29 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) } } + /* + * We use punch hole to reclaim the free space used by the + * image a.k.a. discard. However we do support discard if + * encryption is enabled, because it may give an attacker + * useful information. + */ + if (bio->bi_rw & REQ_DISCARD) { + struct file *file = lo->lo_backing_file; + int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; + + if ((!file->f_op->fallocate) || + lo->lo_encrypt_key_size) { + ret = -EOPNOTSUPP; + goto out; + } + ret = file->f_op->fallocate(file, mode, pos, + bio->bi_size); + if (unlikely(ret && ret != -EINVAL && + ret != -EOPNOTSUPP)) + ret = -EIO; + goto out; + } + ret = lo_send(lo, bio, pos); if ((bio->bi_rw & REQ_FUA) && !ret) { @@ -814,6 +838,35 @@ static void loop_sysfs_exit(struct loop_device *lo) &loop_attribute_group); } +static void loop_config_discard(struct loop_device *lo) +{ + struct file *file = lo->lo_backing_file; + struct inode *inode = file->f_mapping->host; + struct request_queue *q = lo->lo_queue; + + /* + * We use punch hole to reclaim the free space used by the + * image a.k.a. discard. However we do support discard if + * encryption is enabled, because it may give an attacker + * useful information. + */ + if ((!file->f_op->fallocate) || + lo->lo_encrypt_key_size) { + q->limits.discard_granularity = 0; + q->limits.discard_alignment = 0; + q->limits.max_discard_sectors = 0; + q->limits.discard_zeroes_data = 0; + queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); + return; + } + + q->limits.discard_granularity = inode->i_sb->s_blocksize; + q->limits.discard_alignment = inode->i_sb->s_blocksize; + q->limits.max_discard_sectors = UINT_MAX >> 9; + q->limits.discard_zeroes_data = 1; + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); +} + static int loop_set_fd(struct loop_device *lo, fmode_t mode, struct block_device *bdev, unsigned int arg) { @@ -1090,6 +1143,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (figure_loop_size(lo)) return -EFBIG; } + loop_config_discard(lo); memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE); memcpy(lo->lo_crypt_name, info->lo_crypt_name, LO_NAME_SIZE); From d8cb04b070c2a55f7201714d231cff4f8f9fbd16 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 27 Jul 2011 12:21:28 +0000 Subject: [PATCH 0040/1596] dmaengine: at_hdmac: replace spin_lock* with irqsave variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dmaengine routines can be called from interrupt context and with interrupts disabled. Whereas spin_unlock_bh can't be called from such contexts. So this patch converts all spin_lock* routines to irqsave variants. Also, spin_lock() used in tasklet is converted to irqsave variants, as tasklet can be interrupted, and dma requests from such interruptions may also call spin_lock. Idea from dw_dmac patch by Viresh Kumar. Signed-off-by: Nicolas Ferre Signed-off-by: Uwe Kleine-König Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 52 ++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 6a483eac7b3f..fd87b9690e1b 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -107,10 +107,11 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) { struct at_desc *desc, *_desc; struct at_desc *ret = NULL; + unsigned long flags; unsigned int i = 0; LIST_HEAD(tmp_list); - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) { i++; if (async_tx_test_ack(&desc->txd)) { @@ -121,7 +122,7 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) dev_dbg(chan2dev(&atchan->chan_common), "desc %p not ACKed\n", desc); } - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); dev_vdbg(chan2dev(&atchan->chan_common), "scanned %u descriptors on freelist\n", i); @@ -129,9 +130,9 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) if (!ret) { ret = atc_alloc_descriptor(&atchan->chan_common, GFP_ATOMIC); if (ret) { - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); atchan->descs_allocated++; - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } else { dev_err(chan2dev(&atchan->chan_common), "not enough descriptors available\n"); @@ -150,8 +151,9 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) { if (desc) { struct at_desc *child; + unsigned long flags; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); list_for_each_entry(child, &desc->tx_list, desc_node) dev_vdbg(chan2dev(&atchan->chan_common), "moving child desc %p to freelist\n", @@ -160,7 +162,7 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) dev_vdbg(chan2dev(&atchan->chan_common), "moving desc %p to freelist\n", desc); list_add(&desc->desc_node, &atchan->free_list); - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } } @@ -471,8 +473,9 @@ static void atc_handle_cyclic(struct at_dma_chan *atchan) static void atc_tasklet(unsigned long data) { struct at_dma_chan *atchan = (struct at_dma_chan *)data; + unsigned long flags; - spin_lock(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status)) atc_handle_error(atchan); else if (test_bit(ATC_IS_CYCLIC, &atchan->status)) @@ -480,7 +483,7 @@ static void atc_tasklet(unsigned long data) else atc_advance_work(atchan); - spin_unlock(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } static irqreturn_t at_dma_interrupt(int irq, void *dev_id) @@ -539,8 +542,9 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx) struct at_desc *desc = txd_to_at_desc(tx); struct at_dma_chan *atchan = to_at_dma_chan(tx->chan); dma_cookie_t cookie; + unsigned long flags; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); cookie = atc_assign_cookie(atchan, desc); if (list_empty(&atchan->active_list)) { @@ -554,7 +558,7 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx) list_add_tail(&desc->desc_node, &atchan->queue); } - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); return cookie; } @@ -927,28 +931,29 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); int chan_id = atchan->chan_common.chan_id; + unsigned long flags; LIST_HEAD(list); dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd); if (cmd == DMA_PAUSE) { - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id)); set_bit(ATC_IS_PAUSED, &atchan->status); - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_RESUME) { if (!test_bit(ATC_IS_PAUSED, &atchan->status)) return 0; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); dma_writel(atdma, CHDR, AT_DMA_RES(chan_id)); clear_bit(ATC_IS_PAUSED, &atchan->status); - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_TERMINATE_ALL) { struct at_desc *desc, *_desc; /* @@ -957,7 +962,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, * channel. We still have to poll the channel enable bit due * to AHB/HSB limitations. */ - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); /* disabling channel: must also remove suspend state */ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask); @@ -978,7 +983,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, /* if channel dedicated to cyclic operations, free it */ clear_bit(ATC_IS_CYCLIC, &atchan->status); - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } else { return -ENXIO; } @@ -1004,9 +1009,10 @@ atc_tx_status(struct dma_chan *chan, struct at_dma_chan *atchan = to_at_dma_chan(chan); dma_cookie_t last_used; dma_cookie_t last_complete; + unsigned long flags; enum dma_status ret; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); last_complete = atchan->completed_cookie; last_used = chan->cookie; @@ -1021,7 +1027,7 @@ atc_tx_status(struct dma_chan *chan, ret = dma_async_is_complete(cookie, last_complete, last_used); } - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); if (ret != DMA_SUCCESS) dma_set_tx_state(txstate, last_complete, last_used, @@ -1046,6 +1052,7 @@ atc_tx_status(struct dma_chan *chan, static void atc_issue_pending(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); + unsigned long flags; dev_vdbg(chan2dev(chan), "issue_pending\n"); @@ -1053,11 +1060,11 @@ static void atc_issue_pending(struct dma_chan *chan) if (test_bit(ATC_IS_CYCLIC, &atchan->status)) return; - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); if (!atc_chan_is_enabled(atchan)) { atc_advance_work(atchan); } - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); } /** @@ -1073,6 +1080,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) struct at_dma *atdma = to_at_dma(chan->device); struct at_desc *desc; struct at_dma_slave *atslave; + unsigned long flags; int i; u32 cfg; LIST_HEAD(tmp_list); @@ -1116,11 +1124,11 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) list_add_tail(&desc->desc_node, &tmp_list); } - spin_lock_bh(&atchan->lock); + spin_lock_irqsave(&atchan->lock, flags); atchan->descs_allocated = i; list_splice(&tmp_list, &atchan->free_list); atchan->completed_cookie = chan->cookie = 1; - spin_unlock_bh(&atchan->lock); + spin_unlock_irqrestore(&atchan->lock, flags); /* channel parameters */ channel_writel(atchan, CFG, cfg); From c0ba5947370a0900b1823922fc4faf41515bc901 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 27 Jul 2011 12:21:29 +0000 Subject: [PATCH 0041/1596] dmaengine: at_hdmac: improve power management routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Save/restore dma controller state across a suspend-resume sequence. The prepare() function will wait for the non-cyclic channels to become idle. It also deals with cyclic operations with the start at next period while resuming. Signed-off-by: Nicolas Ferre Signed-off-by: Uwe Kleine-König Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 88 ++++++++++++++++++++++++++++++++++++- drivers/dma/at_hdmac_regs.h | 7 +++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index fd87b9690e1b..0ead008e3bdf 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1385,27 +1385,113 @@ static void at_dma_shutdown(struct platform_device *pdev) clk_disable(atdma->clk); } +static int at_dma_prepare(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct at_dma *atdma = platform_get_drvdata(pdev); + struct dma_chan *chan, *_chan; + + list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, + device_node) { + struct at_dma_chan *atchan = to_at_dma_chan(chan); + /* wait for transaction completion (except in cyclic case) */ + if (atc_chan_is_enabled(atchan) && + !test_bit(ATC_IS_CYCLIC, &atchan->status)) + return -EAGAIN; + } + return 0; +} + +static void atc_suspend_cyclic(struct at_dma_chan *atchan) +{ + struct dma_chan *chan = &atchan->chan_common; + + /* Channel should be paused by user + * do it anyway even if it is not done already */ + if (!test_bit(ATC_IS_PAUSED, &atchan->status)) { + dev_warn(chan2dev(chan), + "cyclic channel not paused, should be done by channel user\n"); + atc_control(chan, DMA_PAUSE, 0); + } + + /* now preserve additional data for cyclic operations */ + /* next descriptor address in the cyclic list */ + atchan->save_dscr = channel_readl(atchan, DSCR); + + vdbg_dump_regs(atchan); +} + static int at_dma_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct at_dma *atdma = platform_get_drvdata(pdev); + struct dma_chan *chan, *_chan; - at_dma_off(platform_get_drvdata(pdev)); + /* preserve data */ + list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, + device_node) { + struct at_dma_chan *atchan = to_at_dma_chan(chan); + + if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + atc_suspend_cyclic(atchan); + atchan->save_cfg = channel_readl(atchan, CFG); + } + atdma->save_imr = dma_readl(atdma, EBCIMR); + + /* disable DMA controller */ + at_dma_off(atdma); clk_disable(atdma->clk); return 0; } +static void atc_resume_cyclic(struct at_dma_chan *atchan) +{ + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); + + /* restore channel status for cyclic descriptors list: + * next descriptor in the cyclic list at the time of suspend */ + channel_writel(atchan, SADDR, 0); + channel_writel(atchan, DADDR, 0); + channel_writel(atchan, CTRLA, 0); + channel_writel(atchan, CTRLB, 0); + channel_writel(atchan, DSCR, atchan->save_dscr); + dma_writel(atdma, CHER, atchan->mask); + + /* channel pause status should be removed by channel user + * We cannot take the initiative to do it here */ + + vdbg_dump_regs(atchan); +} + static int at_dma_resume_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct at_dma *atdma = platform_get_drvdata(pdev); + struct dma_chan *chan, *_chan; + /* bring back DMA controller */ clk_enable(atdma->clk); dma_writel(atdma, EN, AT_DMA_ENABLE); + + /* clear any pending interrupt */ + while (dma_readl(atdma, EBCISR)) + cpu_relax(); + + /* restore saved data */ + dma_writel(atdma, EBCIER, atdma->save_imr); + list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, + device_node) { + struct at_dma_chan *atchan = to_at_dma_chan(chan); + + channel_writel(atchan, CFG, atchan->save_cfg); + if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + atc_resume_cyclic(atchan); + } return 0; } static const struct dev_pm_ops at_dma_dev_pm_ops = { + .prepare = at_dma_prepare, .suspend_noirq = at_dma_suspend_noirq, .resume_noirq = at_dma_resume_noirq, }; diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 087dbf1dd39c..6f0c4a3eb091 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -204,6 +204,9 @@ enum atc_status { * @status: transmit status information from irq/prep* functions * to tasklet (use atomic operations) * @tasklet: bottom half to finish transaction work + * @save_cfg: configuration register that is saved on suspend/resume cycle + * @save_dscr: for cyclic operations, preserve next descriptor address in + * the cyclic list on suspend/resume cycle * @lock: serializes enqueue/dequeue operations to descriptors lists * @completed_cookie: identifier for the most recently completed operation * @active_list: list of descriptors dmaengine is being running on @@ -218,6 +221,8 @@ struct at_dma_chan { u8 mask; unsigned long status; struct tasklet_struct tasklet; + u32 save_cfg; + u32 save_dscr; spinlock_t lock; @@ -248,6 +253,7 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan) * @chan_common: common dmaengine dma_device object members * @ch_regs: memory mapped register base * @clk: dma controller clock + * @save_imr: interrupt mask register that is saved on suspend/resume cycle * @all_chan_mask: all channels availlable in a mask * @dma_desc_pool: base of DMA descriptor region (DMA address) * @chan: channels table to store at_dma_chan structures @@ -256,6 +262,7 @@ struct at_dma { struct dma_device dma_common; void __iomem *regs; struct clk *clk; + u32 save_imr; u8 all_chan_mask; From 3c477482bb9f976e5451c50be7d3d60ea6f88646 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 25 Jul 2011 21:09:23 +0000 Subject: [PATCH 0042/1596] dmaengine: at_hdmac: add wrappers for testing channel state Cyclic property and paused state are encoded as bits in the channel status bitfield. Tests of those bits are wrapped in convenient helper functions. Signed-off-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 19 +++++++++---------- drivers/dma/at_hdmac_regs.h | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 0ead008e3bdf..d774800b9fa4 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -301,7 +301,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) /* for cyclic transfers, * no need to replay callback function while stopping */ - if (!test_bit(ATC_IS_CYCLIC, &atchan->status)) { + if (!atc_chan_is_cyclic(atchan)) { dma_async_tx_callback callback = txd->callback; void *param = txd->callback_param; @@ -478,7 +478,7 @@ static void atc_tasklet(unsigned long data) spin_lock_irqsave(&atchan->lock, flags); if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status)) atc_handle_error(atchan); - else if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + else if (atc_chan_is_cyclic(atchan)) atc_handle_cyclic(atchan); else atc_advance_work(atchan); @@ -945,7 +945,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_RESUME) { - if (!test_bit(ATC_IS_PAUSED, &atchan->status)) + if (!atc_chan_is_paused(atchan)) return 0; spin_lock_irqsave(&atchan->lock, flags); @@ -1035,7 +1035,7 @@ atc_tx_status(struct dma_chan *chan, else dma_set_tx_state(txstate, last_complete, last_used, 0); - if (test_bit(ATC_IS_PAUSED, &atchan->status)) + if (atc_chan_is_paused(atchan)) ret = DMA_PAUSED; dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n", @@ -1057,7 +1057,7 @@ static void atc_issue_pending(struct dma_chan *chan) dev_vdbg(chan2dev(chan), "issue_pending\n"); /* Not needed for cyclic transfers */ - if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + if (atc_chan_is_cyclic(atchan)) return; spin_lock_irqsave(&atchan->lock, flags); @@ -1395,8 +1395,7 @@ static int at_dma_prepare(struct device *dev) device_node) { struct at_dma_chan *atchan = to_at_dma_chan(chan); /* wait for transaction completion (except in cyclic case) */ - if (atc_chan_is_enabled(atchan) && - !test_bit(ATC_IS_CYCLIC, &atchan->status)) + if (atc_chan_is_enabled(atchan) && !atc_chan_is_cyclic(atchan)) return -EAGAIN; } return 0; @@ -1408,7 +1407,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan) /* Channel should be paused by user * do it anyway even if it is not done already */ - if (!test_bit(ATC_IS_PAUSED, &atchan->status)) { + if (!atc_chan_is_paused(atchan)) { dev_warn(chan2dev(chan), "cyclic channel not paused, should be done by channel user\n"); atc_control(chan, DMA_PAUSE, 0); @@ -1432,7 +1431,7 @@ static int at_dma_suspend_noirq(struct device *dev) device_node) { struct at_dma_chan *atchan = to_at_dma_chan(chan); - if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + if (atc_chan_is_cyclic(atchan)) atc_suspend_cyclic(atchan); atchan->save_cfg = channel_readl(atchan, CFG); } @@ -1484,7 +1483,7 @@ static int at_dma_resume_noirq(struct device *dev) struct at_dma_chan *atchan = to_at_dma_chan(chan); channel_writel(atchan, CFG, atchan->save_cfg); - if (test_bit(ATC_IS_CYCLIC, &atchan->status)) + if (atc_chan_is_cyclic(atchan)) atc_resume_cyclic(atchan); } return 0; diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 6f0c4a3eb091..aa4c9aebab7c 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -362,6 +362,23 @@ static inline int atc_chan_is_enabled(struct at_dma_chan *atchan) return !!(dma_readl(atdma, CHSR) & atchan->mask); } +/** + * atc_chan_is_paused - test channel pause/resume status + * @atchan: channel we want to test status + */ +static inline int atc_chan_is_paused(struct at_dma_chan *atchan) +{ + return test_bit(ATC_IS_PAUSED, &atchan->status); +} + +/** + * atc_chan_is_cyclic - test if given channel has cyclic property set + * @atchan: channel we want to test status + */ +static inline int atc_chan_is_cyclic(struct at_dma_chan *atchan) +{ + return test_bit(ATC_IS_CYCLIC, &atchan->status); +} /** * set_desc_eol - set end-of-link to descriptor so it will end transfer From d7db80801f8117cf210b9e2cd2c800e326d59fa2 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 5 Aug 2011 11:43:44 +0000 Subject: [PATCH 0043/1596] dmaengine: at_hdmac: fix way to specify cyclic capability In this driver, we can trigger cyclic transfer on peripherals-DMA interfaces. It is dependent on driver implementation but cannot depend on a platform property: we remove the dma_has_cap(DMA_CYCLIC, ) test which has no meaning. Signed-off-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index d774800b9fa4..3b99dc62874b 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1301,15 +1301,13 @@ static int __init at_dma_probe(struct platform_device *pdev) if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask)) atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy; - if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) + if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) { atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg; - - if (dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask)) + /* controller can do slave DMA: can trigger cyclic transfers */ + dma_cap_set(DMA_CYCLIC, atdma->dma_common.cap_mask); atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic; - - if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) || - dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask)) atdma->dma_common.device_control = atc_control; + } dma_writel(atdma, EN, AT_DMA_ENABLE); From d37854cf99319966f34bb19c7a897b87d478b56c Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 22 Aug 2011 16:23:56 +0300 Subject: [PATCH 0044/1596] UBIFS: introduce a helper to dump scanning info This commit adds 'dbg_dump_sleb()' helper function to dump scanning information. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 16 ++++++++++++++++ fs/ubifs/debug.h | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index eef109a1a927..b09ba2dd8b62 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -870,6 +870,22 @@ void dbg_dump_lpt_info(struct ubifs_info *c) spin_unlock(&dbg_lock); } +void dbg_dump_sleb(const struct ubifs_info *c, + const struct ubifs_scan_leb *sleb, int offs) +{ + struct ubifs_scan_node *snod; + + printk(KERN_DEBUG "(pid %d) start dumping scanned data from LEB %d:%d\n", + current->pid, sleb->lnum, offs); + + list_for_each_entry(snod, &sleb->nodes, list) { + cond_resched(); + printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", sleb->lnum, + snod->offs, snod->len); + dbg_dump_node(c, snod->node); + } +} + void dbg_dump_leb(const struct ubifs_info *c, int lnum) { struct ubifs_scan_leb *sleb; diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 45174b534377..2bf84211e320 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -269,6 +269,8 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp); void dbg_dump_lprops(struct ubifs_info *c); void dbg_dump_lpt_info(struct ubifs_info *c); void dbg_dump_leb(const struct ubifs_info *c, int lnum); +void dbg_dump_sleb(const struct ubifs_info *c, + const struct ubifs_scan_leb *sleb, int offs); void dbg_dump_znode(const struct ubifs_info *c, const struct ubifs_znode *znode); void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat); @@ -387,6 +389,9 @@ static inline void dbg_dump_lpt_info(struct ubifs_info *c) { return; } static inline void dbg_dump_leb(const struct ubifs_info *c, int lnum) { return; } static inline void +dbg_dump_sleb(const struct ubifs_info *c, + const struct ubifs_scan_leb *sleb, int offs) { return; } +static inline void dbg_dump_znode(const struct ubifs_info *c, const struct ubifs_znode *znode) { return; } static inline void dbg_dump_heap(struct ubifs_info *c, From d27769ec3df1a8de9ca450d2dcd72d1ab259ba32 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 23 Aug 2011 20:01:04 +0200 Subject: [PATCH 0045/1596] block: add GENHD_FL_NO_PART_SCAN There are cases where suppressing partition scan is useful - e.g. for lo devices and pseudo SATA devices which advertise to be a disk but get upset on partition scan (some port multiplier control devices show such behavior). This patch adds GENHD_FL_NO_PART_SCAN which suppresses partition scan regardless of the number of possible partitions. disk_partitionable() is renamed to disk_part_scan_enabled() as suppressing partition scan doesn't imply the device can't be partitioned using BLKPG_ADD/DEL_PARTITION calls from userland. show_partition() now directly tests disk_max_parts() to maintain backward-compatibility. -v2: Updated to make it clear that only partition scan is suppressed not partitioning itself as suggested by Kay Sievers. Signed-off-by: Tejun Heo Cc: Kay Sievers Signed-off-by: Jens Axboe --- block/genhd.c | 4 ++-- block/ioctl.c | 2 +- fs/block_dev.c | 2 +- include/linux/genhd.h | 6 ++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 5cb51c55f6d8..2429ecbbd97d 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -536,7 +536,7 @@ void register_disk(struct gendisk *disk) disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); /* No minors to use for partitions */ - if (!disk_partitionable(disk)) + if (!disk_part_scan_enabled(disk)) goto exit; /* No such device (e.g., media were just removed) */ @@ -841,7 +841,7 @@ static int show_partition(struct seq_file *seqf, void *v) char buf[BDEVNAME_SIZE]; /* Don't show non-partitionable removeable devices or empty devices */ - if (!get_capacity(sgp) || (!disk_partitionable(sgp) && + if (!get_capacity(sgp) || (!disk_max_parts(sgp) && (sgp->flags & GENHD_FL_REMOVABLE))) return 0; if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO) diff --git a/block/ioctl.c b/block/ioctl.c index 1124cd297263..5c74efc01903 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -101,7 +101,7 @@ static int blkdev_reread_part(struct block_device *bdev) struct gendisk *disk = bdev->bd_disk; int res; - if (!disk_partitionable(disk) || bdev != bdev->bd_contains) + if (!disk_part_scan_enabled(disk) || bdev != bdev->bd_contains) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EACCES; diff --git a/fs/block_dev.c b/fs/block_dev.c index ff77262e887c..0bed0d4588dd 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -971,7 +971,7 @@ static void flush_disk(struct block_device *bdev, bool kill_dirty) if (!bdev->bd_disk) return; - if (disk_partitionable(bdev->bd_disk)) + if (disk_part_scan_enabled(bdev->bd_disk)) bdev->bd_invalidated = 1; } diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 02fa4697a0e5..6d18f3531f18 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -128,6 +128,7 @@ struct hd_struct { #define GENHD_FL_EXT_DEVT 64 /* allow extended devt */ #define GENHD_FL_NATIVE_CAPACITY 128 #define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE 256 +#define GENHD_FL_NO_PART_SCAN 512 enum { DISK_EVENT_MEDIA_CHANGE = 1 << 0, /* media changed */ @@ -234,9 +235,10 @@ static inline int disk_max_parts(struct gendisk *disk) return disk->minors; } -static inline bool disk_partitionable(struct gendisk *disk) +static inline bool disk_part_scan_enabled(struct gendisk *disk) { - return disk_max_parts(disk) > 1; + return disk_max_parts(disk) > 1 && + !(disk->flags & GENHD_FL_NO_PART_SCAN); } static inline dev_t disk_devt(struct gendisk *disk) From e03c8dd14915fabc101aa495828d58598dc5af98 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 23 Aug 2011 20:12:04 +0200 Subject: [PATCH 0046/1596] loop: always allow userspace partitions and optionally support automatic scanning Automatic partition scanning can be requested individually per loop device during its setup by setting LO_FLAGS_PARTSCAN. By default, no partition tables are scanned. Userspace can now always add and remove partitions from all loop devices, regardless if the in-kernel partition scanner is enabled or not. The needed partition minor numbers are allocated from the extended minors space, the main loop device numbers will continue to match the loop minors, regardless of the number of partitions used. # grep . /sys/class/block/loop1/loop/* /sys/block/loop1/loop/autoclear:0 /sys/block/loop1/loop/backing_file:/home/kay/data/stuff/part.img /sys/block/loop1/loop/offset:0 /sys/block/loop1/loop/partscan:1 /sys/block/loop1/loop/sizelimit:0 # ls -l /dev/loop* brw-rw---- 1 root disk 7, 0 Aug 14 20:22 /dev/loop0 brw-rw---- 1 root disk 7, 1 Aug 14 20:23 /dev/loop1 brw-rw---- 1 root disk 259, 0 Aug 14 20:23 /dev/loop1p1 brw-rw---- 1 root disk 259, 1 Aug 14 20:23 /dev/loop1p2 brw-rw---- 1 root disk 7, 99 Aug 14 20:23 /dev/loop99 brw-rw---- 1 root disk 259, 2 Aug 14 20:23 /dev/loop99p1 brw-rw---- 1 root disk 259, 3 Aug 14 20:23 /dev/loop99p2 crw------T 1 root root 10, 237 Aug 14 20:22 /dev/loop-control Cc: Karel Zak Cc: Davidlohr Bueso Acked-By: Tejun Heo Signed-off-by: Kay Sievers Signed-off-by: Jens Axboe --- drivers/block/loop.c | 49 ++++++++++++++++++++++++++++++++++++++++---- include/linux/loop.h | 1 + 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 936cac3c3126..b336433f8157 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -724,7 +724,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, goto out_putf; fput(old_file); - if (max_part > 0) + if (lo->lo_flags & LO_FLAGS_PARTSCAN) ioctl_by_bdev(bdev, BLKRRPART, 0); return 0; @@ -808,16 +808,25 @@ static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf) return sprintf(buf, "%s\n", autoclear ? "1" : "0"); } +static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf) +{ + int partscan = (lo->lo_flags & LO_FLAGS_PARTSCAN); + + return sprintf(buf, "%s\n", partscan ? "1" : "0"); +} + LOOP_ATTR_RO(backing_file); LOOP_ATTR_RO(offset); LOOP_ATTR_RO(sizelimit); LOOP_ATTR_RO(autoclear); +LOOP_ATTR_RO(partscan); static struct attribute *loop_attrs[] = { &loop_attr_backing_file.attr, &loop_attr_offset.attr, &loop_attr_sizelimit.attr, &loop_attr_autoclear.attr, + &loop_attr_partscan.attr, NULL, }; @@ -979,7 +988,9 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, } lo->lo_state = Lo_bound; wake_up_process(lo->lo_thread); - if (max_part > 0) + if (part_shift) + lo->lo_flags |= LO_FLAGS_PARTSCAN; + if (lo->lo_flags & LO_FLAGS_PARTSCAN) ioctl_by_bdev(bdev, BLKRRPART, 0); return 0; @@ -1070,7 +1081,6 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) lo->lo_offset = 0; lo->lo_sizelimit = 0; lo->lo_encrypt_key_size = 0; - lo->lo_flags = 0; lo->lo_thread = NULL; memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); @@ -1088,8 +1098,11 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) lo->lo_state = Lo_unbound; /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); - if (max_part > 0 && bdev) + if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev) ioctl_by_bdev(bdev, BLKRRPART, 0); + lo->lo_flags = 0; + if (!part_shift) + lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; mutex_unlock(&lo->lo_ctl_mutex); /* * Need not hold lo_ctl_mutex to fput backing file. @@ -1159,6 +1172,13 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) (info->lo_flags & LO_FLAGS_AUTOCLEAR)) lo->lo_flags ^= LO_FLAGS_AUTOCLEAR; + if ((info->lo_flags & LO_FLAGS_PARTSCAN) && + !(lo->lo_flags & LO_FLAGS_PARTSCAN)) { + lo->lo_flags |= LO_FLAGS_PARTSCAN; + lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; + ioctl_by_bdev(lo->lo_device, BLKRRPART, 0); + } + lo->lo_encrypt_key_size = info->lo_encrypt_key_size; lo->lo_init[0] = info->lo_init[0]; lo->lo_init[1] = info->lo_init[1]; @@ -1654,6 +1674,27 @@ static struct loop_device *loop_alloc(int i) if (!disk) goto out_free_queue; + /* + * Disable partition scanning by default. The in-kernel partition + * scanning can be requested individually per-device during its + * setup. Userspace can always add and remove partitions from all + * devices. The needed partition minors are allocated from the + * extended minor space, the main loop device numbers will continue + * to match the loop minors, regardless of the number of partitions + * used. + * + * If max_part is given, partition scanning is globally enabled for + * all loop devices. The minors for the main loop devices will be + * multiples of max_part. + * + * Note: Global-for-all-devices, set-only-at-init, read-only module + * parameteters like 'max_loop' and 'max_part' make things needlessly + * complicated, are too static, inflexible and may surprise + * userspace tools. Parameters like this in general should be avoided. + */ + if (!part_shift) + disk->flags |= GENHD_FL_NO_PART_SCAN; + disk->flags |= GENHD_FL_EXT_DEVT; mutex_init(&lo->lo_ctl_mutex); lo->lo_number = i; lo->lo_thread = NULL; diff --git a/include/linux/loop.h b/include/linux/loop.h index 66c194e2d9b9..4367fc507fe9 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -76,6 +76,7 @@ enum { LO_FLAGS_READ_ONLY = 1, LO_FLAGS_USE_AOPS = 2, LO_FLAGS_AUTOCLEAR = 4, + LO_FLAGS_PARTSCAN = 8, }; #include /* for __kernel_old_dev_t */ From 47850a27306997be914dedcbca1dfce09fa4ef0a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:26 +0530 Subject: [PATCH 0047/1596] ARM: asm/pl080.h: Protect against multiple inclusion of header file doesn't have protection to deal with multiple inclusion. And so we get compilation errors in cases where this file is included more than once. This patch adds #ifdefs at the top of file to protect it against multiple inclusions. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- arch/arm/include/asm/hardware/pl080.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/include/asm/hardware/pl080.h b/arch/arm/include/asm/hardware/pl080.h index e4a04e4e5627..33c78d7af2e1 100644 --- a/arch/arm/include/asm/hardware/pl080.h +++ b/arch/arm/include/asm/hardware/pl080.h @@ -21,6 +21,9 @@ * OneNAND features. */ +#ifndef ASM_PL080_H +#define ASM_PL080_H + #define PL080_INT_STATUS (0x00) #define PL080_TC_STATUS (0x04) #define PL080_TC_CLEAR (0x08) @@ -138,3 +141,4 @@ struct pl080s_lli { u32 control1; }; +#endif /* ASM_PL080_H */ From 3e27ee8448bcbc8b4f060b107aa622c116f287ab Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:27 +0530 Subject: [PATCH 0048/1596] dmaengine/amba-pl08x: Resolve formatting issues There were few formatting related issues in code. This patch fixes them. Fixes include: - Remove extra blank lines - align code to 80 cols - combine several lines to one line Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 41 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 196a7378d332..4c4a3092e09c 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -125,7 +125,8 @@ struct pl08x_lli { * @phy_chans: array of data for the physical channels * @pool: a pool for the LLI descriptors * @pool_ctr: counter of LLIs in the pool - * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI fetches + * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI + * fetches * @mem_buses: set to indicate memory transfers on AHB2. * @lock: a spinlock for this struct */ @@ -271,7 +272,6 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch) writel(val, ch->base + PL080_CH_CONFIG); } - /* * pl08x_terminate_phy_chan() stops the channel, clears the FIFO and * clears any pending interrupt status. This should not be used for @@ -546,7 +546,8 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, llis_va[num_llis].cctl = cctl; llis_va[num_llis].src = bd->srcbus.addr; llis_va[num_llis].dst = bd->dstbus.addr; - llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); + llis_va[num_llis].lli = llis_bus + (num_llis + 1) * + sizeof(struct pl08x_lli); llis_va[num_llis].lli |= bd->lli_bus; if (cctl & PL080_CONTROL_SRC_INCR) @@ -583,12 +584,10 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_lli_build_data bd; int num_llis = 0; u32 cctl; - size_t max_bytes_per_lli; - size_t total_bytes = 0; + size_t max_bytes_per_lli, total_bytes = 0; struct pl08x_lli *llis_va; - txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, - &txd->llis_bus); + txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus); if (!txd->llis_va) { dev_err(&pl08x->adev->dev, "%s no memory for llis\n", __func__); return 0; @@ -779,7 +778,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, total_bytes += lli_len; } - if (odd_bytes) { /* * Creep past the boundary, maintaining @@ -916,9 +914,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, * need, but for slaves the physical signals may be muxed! * Can the platform allow us to use this channel? */ - if (plchan->slave && - ch->signal < 0 && - pl08x->pd->get_signal) { + if (plchan->slave && ch->signal < 0 && pl08x->pd->get_signal) { ret = pl08x->pd->get_signal(plchan); if (ret < 0) { dev_dbg(&pl08x->adev->dev, @@ -1007,10 +1003,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt( * If slaves are relying on interrupts to signal completion this function * must not be called with interrupts disabled. */ -static enum dma_status -pl08x_dma_tx_status(struct dma_chan *chan, - dma_cookie_t cookie, - struct dma_tx_state *txstate) +static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); dma_cookie_t last_used; @@ -1588,8 +1582,8 @@ static void pl08x_tasklet(unsigned long data) */ list_for_each_entry(waiting, &pl08x->memcpy.channels, chan.device_node) { - if (waiting->state == PL08X_CHAN_WAITING && - waiting->waiting != NULL) { + if (waiting->state == PL08X_CHAN_WAITING && + waiting->waiting != NULL) { int ret; /* This should REALLY not fail now */ @@ -1684,9 +1678,7 @@ static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan) * Make a local wrapper to hold required data */ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, - struct dma_device *dmadev, - unsigned int channels, - bool slave) + struct dma_device *dmadev, unsigned int channels, bool slave) { struct pl08x_dma_chan *chan; int i; @@ -1836,9 +1828,9 @@ static const struct file_operations pl08x_debugfs_operations = { static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x) { /* Expose a simple debugfs interface to view all clocks */ - (void) debugfs_create_file(dev_name(&pl08x->adev->dev), S_IFREG | S_IRUGO, - NULL, pl08x, - &pl08x_debugfs_operations); + (void) debugfs_create_file(dev_name(&pl08x->adev->dev), + S_IFREG | S_IRUGO, NULL, pl08x, + &pl08x_debugfs_operations); } #else @@ -1973,8 +1965,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) /* Register slave channels */ ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->slave, - pl08x->pd->num_slave_channels, - true); + pl08x->pd->num_slave_channels, true); if (ret <= 0) { dev_warn(&pl08x->adev->dev, "%s failed to enumerate slave channels - %d\n", From 0c38d70139138713e66c6f98e19a0320014476ff Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:28 +0530 Subject: [PATCH 0049/1596] dmaengine/amba-pl08x: Rearrange inclusion of header files in ascending order Header files included in driver are not present in alphabetical order. Rearrange them in alphabetical order. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 4c4a3092e09c..8e2056bf1623 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -74,19 +74,18 @@ * Global TODO: * - Break out common code from arch/arm/mach-s3c64xx and share */ -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include - +#include #include #define DRIVER_NAME "pl08xdmac" From b201c111c87a4cf36d009abe57c62bd14d17d762 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:29 +0530 Subject: [PATCH 0050/1596] dmaengine/amba-pl08x: pass (*ptr) to sizeof() instead of (struct xyz) As mentioned in Documentation/CodingStyle, The preferred form for passing a size of a struct is the following: p = kmalloc(sizeof(*p), ...); The alternative form where struct name is spelled out hurts readability and introduces an opportunity for a bug when the pointer variable type is changed but the corresponding sizeof that is passed to a memory allocator is not. This patch replaces (struct xyz) with *ptr at several occurrences in driver. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 8e2056bf1623..01c2f507e950 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1293,7 +1293,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, unsigned long flags) { - struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); + struct pl08x_txd *txd = kzalloc(sizeof(*txd), GFP_NOWAIT); if (txd) { dma_async_tx_descriptor_init(&txd->tx, &plchan->chan); @@ -1690,7 +1690,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, * to cope with that situation. */ for (i = 0; i < channels; i++) { - chan = kzalloc(sizeof(struct pl08x_dma_chan), GFP_KERNEL); + chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) { dev_err(&pl08x->adev->dev, "%s no memory for channel\n", __func__); @@ -1850,7 +1850,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) return ret; /* Create the driver state holder */ - pl08x = kzalloc(sizeof(struct pl08x_driver_data), GFP_KERNEL); + pl08x = kzalloc(sizeof(*pl08x), GFP_KERNEL); if (!pl08x) { ret = -ENOMEM; goto out_no_pl08x; @@ -1929,7 +1929,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) } /* Initialize physical channels */ - pl08x->phy_chans = kmalloc((vd->channels * sizeof(struct pl08x_phy_chan)), + pl08x->phy_chans = kmalloc((vd->channels * sizeof(*pl08x->phy_chans)), GFP_KERNEL); if (!pl08x->phy_chans) { dev_err(&adev->dev, "%s failed to allocate " From 5a61233073a35a7ae152af77ed80dfc465c38fc7 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:30 +0530 Subject: [PATCH 0051/1596] dmaengine/amba-pl08x: Complete doc comment for struct pl08x_txd Doc comment for struct pl08x_txd was incomplete. Complete that. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- include/linux/amba/pl08x.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index e6e28f37d8ec..cd8f629da58f 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -105,8 +105,16 @@ struct pl08x_phy_chan { /** * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor + * @tx: async tx descriptor + * @node: node for txd list for channels + * @src_addr: src address of txd + * @dst_addr: dst address of txd + * @len: transfer len in bytes + * @direction: direction of transfer * @llis_bus: DMA memory address (physical) start for the LLIs * @llis_va: virtual memory address start for the LLIs + * @cctl: control reg values for current txd + * @ccfg: config reg values for current txd */ struct pl08x_txd { struct dma_async_tx_descriptor tx; From 0532e6fced3c4f6a4eda7f078d8aa36405647c07 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:31 +0530 Subject: [PATCH 0052/1596] dmaengine/amba-pl08x: Remove redundant comment and rewrite original Similar comment is present over routine also pl08x_choose_master_bus(). Keeping one of them. Also rewrite that comment to convey message clearly. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 01c2f507e950..6c52959b00af 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -497,9 +497,13 @@ struct pl08x_lli_build_data { }; /* - * Autoselect a master bus to use for the transfer this prefers the - * destination bus if both available if fixed address on one bus the - * other will be chosen + * Autoselect a master bus to use for the transfer. Slave will be the chosen as + * victim in case src & dest are not similarly aligned. i.e. If after aligning + * masters address with width requirements of transfer (by sending few byte by + * byte data), slave is still not aligned, then its width will be reduced to + * BYTE. + * - prefers the destination bus if both available + * - if fixed address on one bus the other will be chosen */ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) @@ -625,11 +629,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* We need to count this down to zero */ bd.remainder = txd->len; - /* - * Choose bus to align to - * - prefers destination bus if both available - * - if fixed address on one bus chooses other - */ pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu llimax=%zu\n", From 175a5e617cd820d9e22d9e4f6d3ef736b2f874b1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:32 +0530 Subject: [PATCH 0053/1596] dmaengine/amba-pl08x: Changing few prints to dev_dbg from dev_info For 8 memory and 16 slave channels 35 boot print lines are printed. And that is too much. Most of this would be more useful for debugging. So moving few of them to dev_dbg instead of dev_info. Now only 3 prints will be printed. This also rearrange one of the debug message to fit into two lines. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 6c52959b00af..ead88c9a5e93 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1717,7 +1717,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, kfree(chan); continue; } - dev_info(&pl08x->adev->dev, + dev_dbg(&pl08x->adev->dev, "initialize virtual channel \"%s\"\n", chan->name); @@ -1945,9 +1945,8 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&ch->lock); ch->serving = NULL; ch->signal = -1; - dev_info(&adev->dev, - "physical channel %d is %s\n", i, - pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE"); + dev_dbg(&adev->dev, "physical channel %d is %s\n", + i, pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE"); } /* Register as many memcpy channels as there are physical channels */ From b7b6018bad6fd7ebe5a78bda5f2a71a6ecf5406a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:33 +0530 Subject: [PATCH 0054/1596] dmaengine/amba-pl08x: support runtime PM Insert notifiers for the runtime PM API. With this the runtime PM layer kicks in to action where used. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index ead88c9a5e93..5dd97f450925 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -84,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -405,6 +406,7 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, return NULL; } + pm_runtime_get_sync(&pl08x->adev->dev); return ch; } @@ -418,6 +420,8 @@ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x, /* Stop the channel and clear its interrupts */ pl08x_terminate_phy_chan(pl08x, ch); + pm_runtime_put(&pl08x->adev->dev); + /* Mark it as free */ ch->serving = NULL; spin_unlock_irqrestore(&ch->lock, flags); @@ -1855,6 +1859,9 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) goto out_no_pl08x; } + pm_runtime_set_active(&adev->dev); + pm_runtime_enable(&adev->dev); + /* Initialize memcpy engine */ dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask); pl08x->memcpy.dev = &adev->dev; @@ -1992,6 +1999,8 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n", amba_part(adev), amba_rev(adev), (unsigned long long)adev->res.start, adev->irq[0]); + + pm_runtime_put(&adev->dev); return 0; out_no_slave_reg: @@ -2010,6 +2019,9 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) dma_pool_destroy(pl08x->pool); out_no_lli_pool: out_no_platdata: + pm_runtime_put(&adev->dev); + pm_runtime_disable(&adev->dev); + kfree(pl08x); out_no_pl08x: amba_release_regions(adev); From 48a59ef3579492855d41405f8bf0a2983e061976 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:34 +0530 Subject: [PATCH 0055/1596] dmaengine/amba-pl08x: Simplify pl08x_ensure_on() Simply writing 1 on bit 0 is sufficient instead of reading and clearing bits. Also as per manual, for bit 3-31 of DMACConfiguration register: "read undefined, write as 0" So, we must not rely on values read from this registers bit 3-31. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 5dd97f450925..d79688d64886 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1502,13 +1502,7 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) */ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) { - u32 val; - - val = readl(pl08x->base + PL080_CONFIG); - val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE); - /* We implicitly clear bit 1 and that means little-endian mode */ - val |= PL080_CONFIG_ENABLE; - writel(val, pl08x->base + PL080_CONFIG); + writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG); } static void pl08x_unmap_buffers(struct pl08x_txd *txd) From 16ca8105040217acf5b4b506d04bb933fb3a76af Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:35 +0530 Subject: [PATCH 0056/1596] dmaengine/amba-pl08x: No need to check "ch->signal < 0" We have just executed following in pl08x_get_phy_channel(): ch->signal = -1; We don't have to compare "ch->signal < 0", as this will always be true. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index d79688d64886..3653961b6088 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -916,7 +916,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, * need, but for slaves the physical signals may be muxed! * Can the platform allow us to use this channel? */ - if (plchan->slave && ch->signal < 0 && pl08x->pd->get_signal) { + if (plchan->slave && pl08x->pd->get_signal) { ret = pl08x->pd->get_signal(plchan); if (ret < 0) { dev_dbg(&pl08x->adev->dev, From 28da28365da3f3bea1d4b7212a8a40e4b9ac3229 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:36 +0530 Subject: [PATCH 0057/1596] dmaengine/amba-pl08x: Schedule tasklet in case of error interrupt Currently, if error interrupt occurs, nothing is done in interrupt handler (just clearing the interrupts). We must somehow indicate this to the user that DMA is over, due to ERR interrupt or TC interrupt. So, this patch just schedules existing tasklet, with a print showing error interrupt has occurred on which channels. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 44 +++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 3653961b6088..6bba32e5ddb8 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1619,38 +1619,40 @@ static void pl08x_tasklet(unsigned long data) static irqreturn_t pl08x_irq(int irq, void *dev) { struct pl08x_driver_data *pl08x = dev; - u32 mask = 0; - u32 val; - int i; - - val = readl(pl08x->base + PL080_ERR_STATUS); - if (val) { - /* An error interrupt (on one or more channels) */ - dev_err(&pl08x->adev->dev, - "%s error interrupt, register value 0x%08x\n", - __func__, val); - /* - * Simply clear ALL PL08X error interrupts, - * regardless of channel and cause - * FIXME: should be 0x00000003 on PL081 really. - */ - writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR); + u32 mask = 0, err, tc, i; + + /* check & clear - ERR & TC interrupts */ + err = readl(pl08x->base + PL080_ERR_STATUS); + if (err) { + dev_err(&pl08x->adev->dev, "%s error interrupt, register value 0x%08x\n", + __func__, err); + writel(err, pl08x->base + PL080_ERR_CLEAR); } - val = readl(pl08x->base + PL080_INT_STATUS); + tc = readl(pl08x->base + PL080_INT_STATUS); + if (tc) + writel(tc, pl08x->base + PL080_TC_CLEAR); + + if (!err && !tc) + return IRQ_NONE; + for (i = 0; i < pl08x->vd->channels; i++) { - if ((1 << i) & val) { + if (((1 << i) & err) || ((1 << i) & tc)) { /* Locate physical channel */ struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i]; struct pl08x_dma_chan *plchan = phychan->serving; + if (!plchan) { + dev_err(&pl08x->adev->dev, + "%s Error TC interrupt on unused channel: 0x%08x\n", + __func__, i); + continue; + } + /* Schedule tasklet on this channel */ tasklet_schedule(&plchan->tasklet); - mask |= (1 << i); } } - /* Clear only the terminal interrupts on channels we processed */ - writel(mask, pl08x->base + PL080_TC_CLEAR); return mask ? IRQ_HANDLED : IRQ_NONE; } From 16a2e7d359b9fc64fb8a6717c0642691b1e60bb7 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:37 +0530 Subject: [PATCH 0058/1596] dmaengine/amba-pl08x: Get rid of pl08x_pre_boundary() Pl080 Manual says: "Bursts do not cross the 1KB address boundary" We can program the controller to cross 1 KB boundary on a burst and controller can take care of this boundary condition by itself. Following is the discussion with ARM Technical Support Guys (David): [Viresh] Manual says: "Bursts do not cross the 1KB address boundary" What does that actually mean? As, Maximum size transferable with a single LLI is 4095 * 4 =16380 ~ 16KB. So, if we don't have src/dest address aligned to burst size, we can't use this big of an LLI. [David] There is a difference between bursts describing the total data transferred by the DMA controller and AHB bursts. Bursts described by the programmable parameters in the PL080 have no direct connection with the bursts that are seen on the AHB bus. The statement that "Bursts do not cross the 1KB address boundary" in the TRM is referring to AHB bursts, where this limitation is a requirement of the AHB spec. You can still issue bursts within the PL080 that are in excess of 1KB. The PL080 will make sure that its bursts are broken down into legal AHB bursts which will be formatted to ensure that no AHB burst crosses a 1KB boundary. Based on above discussion, this patch removes all code related to 1 KB boundary as we are not required to handle this in driver. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 141 +++++-------------------------------- include/linux/amba/pl08x.h | 2 - 2 files changed, 17 insertions(+), 126 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 6bba32e5ddb8..be9a1c718f9a 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -149,14 +149,6 @@ struct pl08x_driver_data { * PL08X specific defines */ -/* - * Memory boundaries: the manual for PL08x says that the controller - * cannot read past a 1KiB boundary, so these defines are used to - * create transfer LLIs that do not cross such boundaries. - */ -#define PL08X_BOUNDARY_SHIFT (10) /* 1KB 0x400 */ -#define PL08X_BOUNDARY_SIZE (1 << PL08X_BOUNDARY_SHIFT) - /* Size (bytes) of each LLI buffer allocated for one transfer */ # define PL08X_LLI_TSFR_SIZE 0x2000 @@ -567,18 +559,6 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, bd->remainder -= len; } -/* - * Return number of bytes to fill to boundary, or len. - * This calculation works for any value of addr. - */ -static inline size_t pl08x_pre_boundary(u32 addr, size_t len) -{ - size_t boundary_len = PL08X_BOUNDARY_SIZE - - (addr & (PL08X_BOUNDARY_SIZE - 1)); - - return min(boundary_len, len); -} - /* * This fills in the table of LLIs for the transfer descriptor * Note that we assume we never have to change the burst sizes @@ -685,118 +665,30 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * width left */ while (bd.remainder > (mbus->buswidth - 1)) { - size_t lli_len, target_len, tsize, odd_bytes; + size_t lli_len, tsize; /* * If enough left try to send max possible, * otherwise try to send the remainder */ - target_len = min(bd.remainder, max_bytes_per_lli); - + lli_len = min(bd.remainder, max_bytes_per_lli); /* - * Set bus lengths for incrementing buses to the - * number of bytes which fill to next memory boundary, - * limiting on the target length calculated above. + * Check against minimum bus alignment: Calculate actual + * transfer size in relation to bus width and get a + * maximum remainder of the smallest bus width - 1 */ - if (cctl & PL080_CONTROL_SRC_INCR) - bd.srcbus.fill_bytes = - pl08x_pre_boundary(bd.srcbus.addr, - target_len); - else - bd.srcbus.fill_bytes = target_len; - - if (cctl & PL080_CONTROL_DST_INCR) - bd.dstbus.fill_bytes = - pl08x_pre_boundary(bd.dstbus.addr, - target_len); - else - bd.dstbus.fill_bytes = target_len; - - /* Find the nearest */ - lli_len = min(bd.srcbus.fill_bytes, - bd.dstbus.fill_bytes); - - BUG_ON(lli_len > bd.remainder); - - if (lli_len <= 0) { - dev_err(&pl08x->adev->dev, - "%s lli_len is %zu, <= 0\n", - __func__, lli_len); - return 0; - } - - if (lli_len == target_len) { - /* - * Can send what we wanted. - * Maintain alignment - */ - lli_len = (lli_len/mbus->buswidth) * - mbus->buswidth; - odd_bytes = 0; - } else { - /* - * So now we know how many bytes to transfer - * to get to the nearest boundary. The next - * LLI will past the boundary. However, we - * may be working to a boundary on the slave - * bus. We need to ensure the master stays - * aligned, and that we are working in - * multiples of the bus widths. - */ - odd_bytes = lli_len % mbus->buswidth; - lli_len -= odd_bytes; - - } - - if (lli_len) { - /* - * Check against minimum bus alignment: - * Calculate actual transfer size in relation - * to bus width an get a maximum remainder of - * the smallest bus width - 1 - */ - /* FIXME: use round_down()? */ - tsize = lli_len / min(mbus->buswidth, - sbus->buswidth); - lli_len = tsize * min(mbus->buswidth, - sbus->buswidth); - - if (target_len != lli_len) { - dev_vdbg(&pl08x->adev->dev, - "%s can't send what we want. Desired 0x%08zx, lli of 0x%08zx bytes in txd of 0x%08zx\n", - __func__, target_len, lli_len, txd->len); - } - - cctl = pl08x_cctl_bits(cctl, - bd.srcbus.buswidth, - bd.dstbus.buswidth, - tsize); - - dev_vdbg(&pl08x->adev->dev, - "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", - __func__, lli_len, bd.remainder); - pl08x_fill_lli_for_desc(&bd, num_llis++, - lli_len, cctl); - total_bytes += lli_len; - } + tsize = lli_len / min(mbus->buswidth, sbus->buswidth); + lli_len = tsize * min(mbus->buswidth, sbus->buswidth); - if (odd_bytes) { - /* - * Creep past the boundary, maintaining - * master alignment - */ - int j; - for (j = 0; (j < mbus->buswidth) - && (bd.remainder); j++) { - cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single byte (remain 0x%08zx)\n", - __func__, bd.remainder); - pl08x_fill_lli_for_desc(&bd, - num_llis++, 1, cctl); - total_bytes++; - } - } + dev_vdbg(&pl08x->adev->dev, + "%s fill lli with single lli chunk of " + "size 0x%08zx (remainder 0x%08zx)\n", + __func__, lli_len, bd.remainder); + + cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, + bd.dstbus.buswidth, tsize); + pl08x_fill_lli_for_desc(&bd, num_llis++, lli_len, cctl); + total_bytes += lli_len; } /* @@ -811,6 +703,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, total_bytes++; } } + if (total_bytes != txd->len) { dev_err(&pl08x->adev->dev, "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n", diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index cd8f629da58f..ecd17f581e71 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -77,13 +77,11 @@ struct pl08x_channel_data { * @addr: current address * @maxwidth: the maximum width of a transfer on this bus * @buswidth: the width of this bus in bytes: 1, 2 or 4 - * @fill_bytes: bytes required to fill to the next bus memory boundary */ struct pl08x_bus_data { dma_addr_t addr; u8 maxwidth; u8 buswidth; - size_t fill_bytes; }; /** From fa6a940bf129c5417b602a4cdfe88b3dbd8e5898 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:38 +0530 Subject: [PATCH 0059/1596] dmaengine/amba-pl08x: max_bytes_per_lli is TRANSFER_SIZE * src_width (not MIN(width)) max_bytes_per_lli = bd.srcbus.buswidth * PL080_CONTROL_TRANSFER_SIZE_MASK; This is confirmed by ARM support guys. Below is summary of mail exchange with them: [Viresh] What is the total data to be transferred in case source and destination bus widths are different. Suppose, source bus width is 2 bytes and destination is 4 bytes. Now in order to transfer 80 bytes, what should be value of TransferSize field in control reg: 40? or 20?. [David from ARM] The value that is programmed into the TransferSize field should be the number of transfers needed to achieve the required data transfer. So, to transfer 80 bytes, with a Source Width of 2, the TransferSize field = should be programmed with: Total transfer size ------------------- = 40 [Viresh] Will this change if source is 4 bytes and dest is 2? [David] Yes - the calculation then becomes: Total transfer size ------------------- =20 Also, max_bytes_per_lli must be calculated after fixing src and dest widths not before that. So move this code to the correct place. This patch also removes max_bytes_per_lli from earlier print message, as till that point max_bytes_per_lli is unknown. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index be9a1c718f9a..e5930d512b00 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -604,23 +604,17 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, bd.srcbus.buswidth = bd.srcbus.maxwidth; bd.dstbus.buswidth = bd.dstbus.maxwidth; - /* - * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) - */ - max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) * - PL080_CONTROL_TRANSFER_SIZE_MASK; - /* We need to count this down to zero */ bd.remainder = txd->len; pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); - dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu llimax=%zu\n", + dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu\n", bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "", bd.srcbus.buswidth, bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "", bd.dstbus.buswidth, - bd.remainder, max_bytes_per_lli); + bd.remainder); dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n", mbus == &bd.srcbus ? "src" : "dst", sbus == &bd.srcbus ? "src" : "dst"); @@ -660,6 +654,10 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, sbus->buswidth = 1; } + /* Bytes transferred = tsize * src width, not MIN(buswidths) */ + max_bytes_per_lli = bd.srcbus.buswidth * + PL080_CONTROL_TRANSFER_SIZE_MASK; + /* * Make largest possible LLIs until less than one bus * width left From 03af500f743f486648fc8afc38593e9844411945 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:39 +0530 Subject: [PATCH 0060/1596] dmaengine/amba-pl08x: Add prep_single_byte_llis() routine Code for creating single byte llis is present at several places. Create a routine to avoid code redundancy. Also, we don't need one lli per single byte transfer, we can have single lli to do all single byte transfer. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 61 ++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index e5930d512b00..45d8a5d5bccd 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -559,6 +559,14 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, bd->remainder -= len; } +static inline void prep_byte_width_lli(struct pl08x_lli_build_data *bd, + u32 *cctl, u32 len, int num_llis, size_t *total_bytes) +{ + *cctl = pl08x_cctl_bits(*cctl, 1, 1, len); + pl08x_fill_lli_for_desc(bd, num_llis, len, *cctl); + (*total_bytes) += len; +} + /* * This fills in the table of LLIs for the transfer descriptor * Note that we assume we never have to change the burst sizes @@ -570,7 +578,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_bus_data *mbus, *sbus; struct pl08x_lli_build_data bd; int num_llis = 0; - u32 cctl; + u32 cctl, early_bytes = 0; size_t max_bytes_per_lli, total_bytes = 0; struct pl08x_lli *llis_va; @@ -619,29 +627,27 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, mbus == &bd.srcbus ? "src" : "dst", sbus == &bd.srcbus ? "src" : "dst"); - if (txd->len < mbus->buswidth) { - /* Less than a bus width available - send as single bytes */ - while (bd.remainder) { - dev_vdbg(&pl08x->adev->dev, - "%s single byte LLIs for a transfer of " - "less than a bus width (remain 0x%08x)\n", - __func__, bd.remainder); - cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); - total_bytes++; - } - } else { - /* Make one byte LLIs until master bus is aligned */ - while ((mbus->addr) % (mbus->buswidth)) { - dev_vdbg(&pl08x->adev->dev, - "%s adjustment lli for less than bus width " - "(remain 0x%08x)\n", - __func__, bd.remainder); - cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); - total_bytes++; - } + /* + * Send byte by byte for following cases + * - Less than a bus width available + * - until master bus is aligned + */ + if (bd.remainder < mbus->buswidth) + early_bytes = bd.remainder; + else if ((mbus->addr) % (mbus->buswidth)) { + early_bytes = mbus->buswidth - (mbus->addr) % (mbus->buswidth); + if ((bd.remainder - early_bytes) < mbus->buswidth) + early_bytes = bd.remainder; + } + + if (early_bytes) { + dev_vdbg(&pl08x->adev->dev, "%s byte width LLIs " + "(remain 0x%08x)\n", __func__, bd.remainder); + prep_byte_width_lli(&bd, &cctl, early_bytes, num_llis++, + &total_bytes); + } + if (bd.remainder) { /* * Master now aligned * - if slave is not then we must set its width down @@ -692,13 +698,12 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* * Send any odd bytes */ - while (bd.remainder) { - cctl = pl08x_cctl_bits(cctl, 1, 1, 1); + if (bd.remainder) { dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single odd byte (remain %zu)\n", + "%s align with boundary, send odd bytes (remain %zu)\n", __func__, bd.remainder); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); - total_bytes++; + prep_byte_width_lli(&bd, &cctl, bd.remainder, + num_llis++, &total_bytes); } } From e0719165801fad04073e7dcd90e4afd02aba3fb7 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:40 +0530 Subject: [PATCH 0061/1596] dmaengine/amba-pl08x: Align lli_len to max(src.width, dst.width) Currently lli_len is aligned to min of two widths, which looks to be incorrect. Instead it should be aligned to max of both widths. Lets say, total_size = 441 bytes MIN: lets check if min() suits or not: CASE 1: srcwidth = 1, dstwidth = 4 min(src, dst) = 1 i.e. We program transfer size in control reg to 441. Now, till 440 bytes everything is fine, but on the last byte DMAC can't transfer 1 byte to dst, as its width is 4. CASE 2: srcwidth = 4, dstwidth = 1 min(src, dst) = 1 i.e. we program transfer size in control reg to 110 (data transferred = 110 * srcwidth). So, here too 1 byte is left, but on the source side. MAX: Lets check if max() suits or not: CASE 3: srcwidth = 1, dstwidth = 4 max(src, dst) = 4 Aligned size is 440 i.e. We program transfer size in control reg to 440. Now, all 440 bytes will be transferred without any issues. CASE 4: srcwidth = 4, dstwidth = 1 max(src, dst) = 4 Aligned size is 440 i.e. We program transfer size in control reg to 110 (data transferred = 110 * srcwidth). Now, also all 440 bytes will be transferred without any issues. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 45d8a5d5bccd..4bcf6036f35d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -669,20 +669,22 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * width left */ while (bd.remainder > (mbus->buswidth - 1)) { - size_t lli_len, tsize; + size_t lli_len, tsize, width; /* * If enough left try to send max possible, * otherwise try to send the remainder */ lli_len = min(bd.remainder, max_bytes_per_lli); + /* - * Check against minimum bus alignment: Calculate actual + * Check against maximum bus alignment: Calculate actual * transfer size in relation to bus width and get a - * maximum remainder of the smallest bus width - 1 + * maximum remainder of the highest bus width - 1 */ - tsize = lli_len / min(mbus->buswidth, sbus->buswidth); - lli_len = tsize * min(mbus->buswidth, sbus->buswidth); + width = max(mbus->buswidth, sbus->buswidth); + lli_len = (lli_len / width) * width; + tsize = lli_len / bd.srcbus.buswidth; dev_vdbg(&pl08x->adev->dev, "%s fill lli with single lli chunk of " From 036f05fd6dcdb6a6b9e55703cb663112fa4c4e42 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:41 +0530 Subject: [PATCH 0062/1596] dmaengine/amba-pl08x: Choose peripheral bus as master bus When we have DMA transfers between peripheral and memory, then we shouldn't reduce width of peripheral at all, as that may be a strict requirement. But we can always reduce width of memory access, with some compromise in performance. Thus, we must select peripheral as master and not memory. Also this rearranges code to make it shorter. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 4bcf6036f35d..f70aa574c58f 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -499,34 +499,24 @@ struct pl08x_lli_build_data { * byte data), slave is still not aligned, then its width will be reduced to * BYTE. * - prefers the destination bus if both available - * - if fixed address on one bus the other will be chosen + * - prefers bus with fixed address (i.e. peripheral) */ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) { if (!(cctl & PL080_CONTROL_DST_INCR)) { - *mbus = &bd->srcbus; - *sbus = &bd->dstbus; - } else if (!(cctl & PL080_CONTROL_SRC_INCR)) { *mbus = &bd->dstbus; *sbus = &bd->srcbus; + } else if (!(cctl & PL080_CONTROL_SRC_INCR)) { + *mbus = &bd->srcbus; + *sbus = &bd->dstbus; } else { - if (bd->dstbus.buswidth == 4) { - *mbus = &bd->dstbus; - *sbus = &bd->srcbus; - } else if (bd->srcbus.buswidth == 4) { - *mbus = &bd->srcbus; - *sbus = &bd->dstbus; - } else if (bd->dstbus.buswidth == 2) { + if (bd->dstbus.buswidth >= bd->srcbus.buswidth) { *mbus = &bd->dstbus; *sbus = &bd->srcbus; - } else if (bd->srcbus.buswidth == 2) { + } else { *mbus = &bd->srcbus; *sbus = &bd->dstbus; - } else { - /* bd->srcbus.buswidth == 1 */ - *mbus = &bd->dstbus; - *sbus = &bd->srcbus; } } } From 0a2356572b1910cc977f4ccf3c9ee1ecab08327a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:42 +0530 Subject: [PATCH 0063/1596] dmaengine/amba-pl08x: Pass flow controller information with slave channel data At least, on SPEAr platforms there is one peripheral, JPEG, which can be flow controller for DMA transfer. Currently DMA controller driver didn't support peripheral flow controller configurations. This patch adds device_fc field in struct pl08x_channel_data, which will be used only for slave transfers and is not used in case of mem2mem transfers. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 61 +++++++++++++++++++++++++++++++++----- include/linux/amba/pl08x.h | 4 +++ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index f70aa574c58f..a59c3c47286c 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -66,11 +66,6 @@ * after the final transfer signalled by LBREQ or LSREQ. The DMAC * will then move to the next LLI entry. * - * Only the former works sanely with scatter lists, so we only implement - * the DMAC flow control method. However, peripherals which use the LBREQ - * and LSREQ signals (eg, MMCI) are unable to use this mode, which through - * these hardware restrictions prevents them from using scatter DMA. - * * Global TODO: * - Break out common code from arch/arm/mach-s3c64xx and share */ @@ -617,6 +612,49 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, mbus == &bd.srcbus ? "src" : "dst", sbus == &bd.srcbus ? "src" : "dst"); + /* + * Zero length is only allowed if all these requirements are met: + * - flow controller is peripheral. + * - src.addr is aligned to src.width + * - dst.addr is aligned to dst.width + * + * sg_len == 1 should be true, as there can be two cases here: + * - Memory addresses are contiguous and are not scattered. Here, Only + * one sg will be passed by user driver, with memory address and zero + * length. We pass this to controller and after the transfer it will + * receive the last burst request from peripheral and so transfer + * finishes. + * + * - Memory addresses are scattered and are not contiguous. Here, + * Obviously as DMA controller doesn't know when a lli's transfer gets + * over, it can't load next lli. So in this case, there has to be an + * assumption that only one lli is supported. Thus, we can't have + * scattered addresses. + */ + if (!bd.remainder) { + u32 fc = (txd->ccfg & PL080_CONFIG_FLOW_CONTROL_MASK) >> + PL080_CONFIG_FLOW_CONTROL_SHIFT; + if (!((fc >= PL080_FLOW_SRC2DST_DST) && + (fc <= PL080_FLOW_SRC2DST_SRC))) { + dev_err(&pl08x->adev->dev, "%s sg len can't be zero", + __func__); + return 0; + } + + if ((bd.srcbus.addr % bd.srcbus.buswidth) || + (bd.srcbus.addr % bd.srcbus.buswidth)) { + dev_err(&pl08x->adev->dev, + "%s src & dst address must be aligned to src" + " & dst width if peripheral is flow controller", + __func__); + return 0; + } + + cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, + bd.dstbus.buswidth, 0); + pl08x_fill_lli_for_desc(&bd, num_llis++, 0, cctl); + } + /* * Send byte by byte for following cases * - Less than a bus width available @@ -1250,7 +1288,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; - int ret; + int ret, tmp; /* * Current implementation ASSUMES only one sg @@ -1284,12 +1322,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( txd->len = sgl->length; if (direction == DMA_TO_DEVICE) { - txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl = plchan->dst_cctl; txd->src_addr = sgl->dma_address; txd->dst_addr = plchan->dst_addr; } else if (direction == DMA_FROM_DEVICE) { - txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl = plchan->src_cctl; txd->src_addr = plchan->src_addr; txd->dst_addr = sgl->dma_address; @@ -1299,6 +1335,15 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( return NULL; } + if (plchan->cd->device_fc) + tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER_PER : + PL080_FLOW_PER2MEM_PER; + else + tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER : + PL080_FLOW_PER2MEM; + + txd->ccfg |= tmp << PL080_CONFIG_FLOW_CONTROL_SHIFT; + ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index ecd17f581e71..a22662c93981 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -47,6 +47,9 @@ enum { * @muxval: a number usually used to poke into some mux regiser to * mux in the signal to this channel * @cctl_opt: default options for the channel control register + * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave + * channels. Fill with 'true' if peripheral should be flow controller. Direction + * will be selected at Runtime. * @addr: source/target address in physical memory for this DMA channel, * can be the address of a FIFO register for burst requests for example. * This can be left undefined if the PrimeCell API is used for configuring @@ -65,6 +68,7 @@ struct pl08x_channel_data { int max_signal; u32 muxval; u32 cctl; + bool device_fc; dma_addr_t addr; bool circular_buffer; bool single; From 57001a606f845ce2eda21a0f23e6aab20ee0cb04 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:45 +0530 Subject: [PATCH 0064/1596] dmaengine/amba-pl08x: Call pl08x_free_txd() instead of calling kfree() directly pl08x_prep_channel_resources() is calling kfree() directly for txd(). To maintain consistency in code call pl08x_free_txd() instead. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index a59c3c47286c..849eab85514b 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1174,7 +1174,9 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, num_llis = pl08x_fill_llis_for_desc(pl08x, txd); if (!num_llis) { - kfree(txd); + spin_lock_irqsave(&plchan->lock, flags); + pl08x_free_txd(pl08x, txd); + spin_unlock_irqrestore(&plchan->lock, flags); return -EINVAL; } From a78f6787a3dd7223bf185895fdcea661b408dc0a Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 17:18:08 +0000 Subject: [PATCH 0065/1596] DocBook/drm: Eradicate inappropriate uses of the future tense Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 50 +++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index c27915893974..0527ff2be37e 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -57,10 +57,10 @@ existing drivers. - First, we'll go over some typical driver initialization + First, we go over some typical driver initialization requirements, like setting up command buffers, creating an initial output configuration, and initializing core services. - Subsequent sections will cover core internals in more detail, + Subsequent sections cover core internals in more detail, providing implementation notes and examples. @@ -74,7 +74,7 @@ The core of every DRM driver is struct drm_driver. Drivers - will typically statically initialize a drm_driver structure, + typically statically initialize a drm_driver structure, then pass it to drm_init() at load time. @@ -155,7 +155,7 @@ In the example above, taken from the i915 DRM driver, the driver sets several flags indicating what core features it supports. - We'll go over the individual callbacks in later sections. Since + We go over the individual callbacks in later sections. Since flags indicate which features your driver supports to the DRM core, you need to set most of them prior to calling drm_init(). Some, like DRIVER_MODESET can be set later based on user supplied parameters, @@ -238,7 +238,7 @@ In this specific case, the driver requires AGP and supports - IRQs. DMA, as we'll see, is handled by device specific ioctls + IRQs. DMA, as discussed later, is handled by device specific ioctls in this case. It also supports the kernel mode setting APIs, though unlike in the actual i915 driver source, this example unconditionally exports KMS capability. @@ -315,7 +315,7 @@ Configuring the device - Obviously, device configuration will be device specific. + Obviously, device configuration is device specific. However, there are several common operations: finding a device's PCI resources, mapping them, and potentially setting up an IRQ handler. @@ -326,7 +326,7 @@ drm_get_resource_len() can be used to find BARs on the given drm_device struct. Once those values have been retrieved, the driver load function can call drm_addmap() to create a new - mapping for the BAR in question. Note you'll probably want a + mapping for the BAR in question. Note you probably want a drm_local_map_t in your driver private structure to track any mappings you create. @@ -357,7 +357,7 @@ - Once your interrupt handler is registered (it'll use your + Once your interrupt handler is registered (it uses your drm_driver.irq_handler as the actual interrupt handling function), you can safely enable interrupts on your device, assuming any other state your interrupt handler uses is also @@ -389,7 +389,7 @@ should support a memory manager. - If your driver supports memory management (it should!), you'll + If your driver supports memory management (it should!), you need to set that up at load time as well. How you initialize it depends on which memory manager you're using, TTM or GEM. @@ -430,13 +430,13 @@ have a type of TTM_GLOBAL_TTM_MEM. The size field for the global object should be sizeof(struct ttm_mem_global), and the init and release hooks should point at your driver specific init and - release routines, which will probably eventually call + release routines, which probably eventually call ttm_mem_global_init and ttm_mem_global_release respectively. Once your global TTM accounting structure is set up and initialized (done by calling ttm_global_item_ref on the global object you - just created), you'll need to create a buffer object TTM to + just created), you need to create a buffer object TTM to provide a pool for buffer object allocation by clients and the kernel itself. The type of this object should be TTM_GLOBAL_TTM_BO, and its size should be sizeof(struct ttm_bo_global). Again, @@ -455,8 +455,8 @@ than TTM, but has no VRAM management capability. Core GEM initialization is comprised of a basic drm_mm_init call to create a GTT DRM MM object, which provides an address space pool for - object allocation. In a KMS configuration, the driver will - need to allocate and initialize a command ring buffer following + object allocation. In a KMS configuration, the driver + needs to allocate and initialize a command ring buffer following basic GEM initialization. Most UMA devices have a so-called "stolen" memory region, which provides space for the initial framebuffer and large, contiguous memory regions required by the @@ -464,16 +464,16 @@ be initialized separately into its own DRM MM object. - Initialization will be driver specific, and will depend on + Initialization is driver specific, and depends on the architecture of the device. In the case of Intel integrated graphics chips like 965GM, GEM initialization can be done by calling the internal GEM init function, i915_gem_do_init(). Since the 965GM is a UMA device - (i.e. it doesn't have dedicated VRAM), GEM will manage + (i.e. it doesn't have dedicated VRAM), GEM manages making regular RAM available for GPU operations. Memory set aside by the BIOS (called "stolen" memory by the i915 - driver) will be managed by the DRM memrange allocator; the - rest of the aperture will be managed by GEM. + driver) is managed by the DRM memrange allocator; the + rest of the aperture is managed by GEM. /* Basic memrange allocator for stolen space (aka vram) */ drm_memrange_init(&dev_priv->vram, 0, prealloc_size); @@ -616,7 +616,7 @@ void intel_crt_init(struct drm_device *dev) DRM_IOCTL_MODESET_CTL should be called by application level drivers before and after mode setting, since on many devices the - vertical blank counter will be reset at that time. Internally, + vertical blank counter is reset at that time. Internally, the DRM snapshots the last vblank count when the ioctl is called with the _DRM_PRE_MODESET command so that the counter won't go backwards (which is dealt with when _DRM_POST_MODESET is used). @@ -632,8 +632,8 @@ void intel_crt_init(struct drm_device *dev) register. The enable and disable vblank callbacks should enable and disable vertical blank interrupts, respectively. In the absence of DRM clients waiting on vblank events, the core DRM - code will use the disable_vblank() function to disable - interrupts, which saves power. They'll be re-enabled again when + code uses the disable_vblank() function to disable + interrupts, which saves power. They are re-enabled again when a client calls the vblank wait ioctl above. @@ -699,14 +699,14 @@ void intel_crt_init(struct drm_device *dev) performs any necessary flushing or synchronization to put the object into the desired coherency domain (note that the object may be busy, i.e. an active render target; in that case the set domain function - will block the client and wait for rendering to complete before + blocks the client and waits for rendering to complete before performing any necessary flushing operations). Perhaps the most important GEM function is providing a command execution interface to clients. Client programs construct command buffers containing references to previously allocated memory objects - and submit them to GEM. At that point, GEM will take care to bind + and submit them to GEM. At that point, GEM takes care to bind all the objects into the GTT, execute the buffer, and provide necessary synchronization between clients accessing the same buffers. This often involves evicting some objects from the GTT and re-binding @@ -767,7 +767,7 @@ void intel_crt_init(struct drm_device *dev) In order to set a mode on a given CRTC, encoder and connector configuration, clients need to provide a framebuffer object which - will provide a source of pixels for the CRTC to deliver to the encoder(s) + provides a source of pixels for the CRTC to deliver to the encoder(s) and ultimately the connector(s) in the configuration. A framebuffer is fundamentally a driver specific memory object, made into an opaque handle by the DRM addfb function. Once an fb has been created this @@ -789,7 +789,7 @@ void intel_crt_init(struct drm_device *dev) The DRM core provides some suspend/resume code, but drivers wanting full suspend/resume support should provide save() and - restore() functions. These will be called at suspend, + restore() functions. These are called at suspend, hibernate, or resume time, and should perform any state save or restore required by your device across suspend or hibernate states. @@ -823,7 +823,7 @@ void intel_crt_init(struct drm_device *dev) Cover generic ioctls and sysfs layout here. Only need high - level info, since man pages will cover the rest. + level info, since man pages should cover the rest. From f11aca045c165b9d4c9c4fce29f51ec24bcf64d3 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 17:21:31 +0000 Subject: [PATCH 0066/1596] DocBook/drm: can -> may Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 0527ff2be37e..b9079386040d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -32,7 +32,7 @@ The Linux DRM layer contains code intended to support the needs of complex graphics devices, usually containing programmable pipelines well suited to 3D graphics acceleration. Graphics - drivers in the kernel can make use of DRM functions to make + drivers in the kernel may make use of DRM functions to make tasks like memory management, interrupt handling and DMA easier, and provide a uniform interface to applications. @@ -293,12 +293,12 @@ can be used for tracking various device specific bits of information, like register offsets, command buffer status, register state for suspend/resume, etc. At load time, a - driver can simply allocate one and set drm_device.dev_priv + driver may simply allocate one and set drm_device.dev_priv appropriately; at unload the driver can free it and set drm_device.dev_priv to NULL. - The DRM supports several counters which can be used for rough + The DRM supports several counters which may be used for rough performance characterization. Note that the DRM stat counter system is not often used by applications, and supporting additional counters is completely optional. @@ -323,7 +323,7 @@ Finding & mapping resources is fairly straightforward. The DRM wrapper functions, drm_get_resource_start() and - drm_get_resource_len() can be used to find BARs on the given + drm_get_resource_len() may be used to find BARs on the given drm_device struct. Once those values have been retrieved, the driver load function can call drm_addmap() to create a new mapping for the BAR in question. Note you probably want a @@ -335,12 +335,12 @@ if compatibility with other operating systems isn't a concern (DRM drivers can run under various BSD variants and OpenSolaris), - native Linux calls can be used for the above, e.g. pci_resource_* + native Linux calls may be used for the above, e.g. pci_resource_* and iomap*/iounmap. See the Linux device driver book for more info. - Once you have a register map, you can use the DRM_READn() and + Once you have a register map, you may use the DRM_READn() and DRM_WRITEn() macros to access the registers on your device, or use driver specific versions to offset into your MMIO space relative to a driver specific base pointer (see I915_READ for @@ -440,7 +440,7 @@ provide a pool for buffer object allocation by clients and the kernel itself. The type of this object should be TTM_GLOBAL_TTM_BO, and its size should be sizeof(struct ttm_bo_global). Again, - driver specific init and release functions can be provided, + driver specific init and release functions may be provided, likely eventually calling ttm_bo_global_init and ttm_bo_global_release, respectively. Also like the previous object, ttm_global_item_ref is used to create an initial reference @@ -483,7 +483,7 @@ - Once the memory manager has been set up, we can allocate the + Once the memory manager has been set up, we may allocate the command buffer. In the i915 case, this is also done with a GEM function, i915_gem_init_ringbuffer(). @@ -572,7 +572,7 @@ void intel_crt_init(struct drm_device *dev) devices with PC-style architectures (i.e. a set of display planes for feeding pixels to encoders which are in turn routed to connectors). Devices with more complex requirements needing - finer grained management can opt to use the core callbacks + finer grained management may opt to use the core callbacks directly. @@ -637,7 +637,7 @@ void intel_crt_init(struct drm_device *dev) a client calls the vblank wait ioctl above. - Devices that don't provide a count register can simply use an + Devices that don't provide a count register may simply use an internal atomic counter incremented on every vertical blank interrupt, and can make their enable and disable vblank functions into no-ops. From 7606f85a701ed8feeac065e133ff9a51c267aa0d Mon Sep 17 00:00:00 2001 From: srimugunthan dhandapani Date: Fri, 26 Aug 2011 16:08:39 +0530 Subject: [PATCH 0067/1596] UBIFS: fix the dark space calculation The dark space calculation should be 64 bit type-casted, when assigning to tmp64 (similar to how total_free is calculated). Overflow will occur for very large flashes. Signed-off-by: srimugunthan Signed-off-by: Artem Bityutskiy --- fs/ubifs/recovery.c | 2 +- fs/ubifs/sb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index af02790d9328..ee4f43f4bb99 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -983,7 +983,7 @@ int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf) } /** - * clean_an_unclean_leb - read and write a LEB to remove corruption. + * clean_an_unclean_leb - read and write a LEB to remove corruption. * @c: UBIFS file-system description object * @ucleb: unclean LEB information * @sbuf: LEB-sized buffer to use diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c index 93d938ad3d2a..6094c5a5d7a8 100644 --- a/fs/ubifs/sb.c +++ b/fs/ubifs/sb.c @@ -247,7 +247,7 @@ static int create_default_filesystem(struct ubifs_info *c) mst->total_dirty = cpu_to_le64(tmp64); /* The indexing LEB does not contribute to dark space */ - tmp64 = (c->main_lebs - 1) * c->dark_wm; + tmp64 = ((long long)(c->main_lebs - 1) * c->dark_wm); mst->total_dark = cpu_to_le64(tmp64); mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ); From 09dafe9e4e266c7868454a532c9ca762aa5c40a5 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 18 Aug 2011 04:32:08 +0000 Subject: [PATCH 0068/1596] ARM: mach-shmobile: sh73a0 PFC pull-up support for SDHI0+2 Extend the existing sh73a0 PFC code with pull-ups for SDHI0 and SDHI2. Without this patch only SDHI1 has pull-up support on sh73a0. Needed by boards that make use of the internal pull-up resistor support built in the SoC. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/include/mach/sh73a0.h | 13 ++++ arch/arm/mach-shmobile/pfc-sh73a0.c | 77 ++++++++++++++++---- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h index 216c3d695ef1..b385e976797a 100644 --- a/arch/arm/mach-shmobile/include/mach/sh73a0.h +++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h @@ -451,11 +451,23 @@ enum { GPIO_FN_KEYIN5_PU, GPIO_FN_KEYIN6_PU, GPIO_FN_KEYIN7_PU, + GPIO_FN_SDHICD0_PU, + GPIO_FN_SDHID0_0_PU, + GPIO_FN_SDHID0_1_PU, + GPIO_FN_SDHID0_2_PU, + GPIO_FN_SDHID0_3_PU, + GPIO_FN_SDHICMD0_PU, + GPIO_FN_SDHIWP0_PU, GPIO_FN_SDHID1_0_PU, GPIO_FN_SDHID1_1_PU, GPIO_FN_SDHID1_2_PU, GPIO_FN_SDHID1_3_PU, GPIO_FN_SDHICMD1_PU, + GPIO_FN_SDHID2_0_PU, + GPIO_FN_SDHID2_1_PU, + GPIO_FN_SDHID2_2_PU, + GPIO_FN_SDHID2_3_PU, + GPIO_FN_SDHICMD2_PU, GPIO_FN_MMCCMD0_PU, GPIO_FN_MMCCMD1_PU, GPIO_FN_FSIACK_PU, @@ -463,6 +475,7 @@ enum { GPIO_FN_FSIAIBT_PU, GPIO_FN_FSIAISLD_PU, }; + /* DMA slave IDs */ enum { SHDMA_SLAVE_INVALID, diff --git a/arch/arm/mach-shmobile/pfc-sh73a0.c b/arch/arm/mach-shmobile/pfc-sh73a0.c index 3eed44eb98b4..a26d9059036b 100644 --- a/arch/arm/mach-shmobile/pfc-sh73a0.c +++ b/arch/arm/mach-shmobile/pfc-sh73a0.c @@ -488,13 +488,26 @@ enum { KEYIN5_PU_MARK, KEYIN6_PU_MARK, KEYIN7_PU_MARK, + SDHICD0_PU_MARK, + SDHID0_0_PU_MARK, + SDHID0_1_PU_MARK, + SDHID0_2_PU_MARK, + SDHID0_3_PU_MARK, + SDHICMD0_PU_MARK, + SDHIWP0_PU_MARK, SDHID1_0_PU_MARK, SDHID1_1_PU_MARK, SDHID1_2_PU_MARK, SDHID1_3_PU_MARK, SDHICMD1_PU_MARK, + SDHID2_0_PU_MARK, + SDHID2_1_PU_MARK, + SDHID2_2_PU_MARK, + SDHID2_3_PU_MARK, + SDHICMD2_PU_MARK, MMCCMD0_PU_MARK, MMCCMD1_PU_MARK, + FSIBISLD_PU_MARK, FSIACK_PU_MARK, FSIAILR_PU_MARK, FSIAIBT_PU_MARK, @@ -1387,19 +1400,28 @@ static pinmux_enum_t pinmux_data[] = { PINMUX_DATA(TS_SCK4_MARK, PORT268_FN3), PINMUX_DATA(SDHICMD2_MARK, PORT269_FN1), PINMUX_DATA(MMCCLK0_MARK, PORT270_FN1, MSEL4CR_MSEL15_0), - PINMUX_DATA(MMCD0_0_MARK, PORT271_FN1, MSEL4CR_MSEL15_0), - PINMUX_DATA(MMCD0_1_MARK, PORT272_FN1, MSEL4CR_MSEL15_0), - PINMUX_DATA(MMCD0_2_MARK, PORT273_FN1, MSEL4CR_MSEL15_0), - PINMUX_DATA(MMCD0_3_MARK, PORT274_FN1, MSEL4CR_MSEL15_0), - PINMUX_DATA(MMCD0_4_MARK, PORT275_FN1, MSEL4CR_MSEL15_0), \ + PINMUX_DATA(MMCD0_0_MARK, PORT271_FN1, PORT271_IN_PU, + MSEL4CR_MSEL15_0), + PINMUX_DATA(MMCD0_1_MARK, PORT272_FN1, PORT272_IN_PU, + MSEL4CR_MSEL15_0), + PINMUX_DATA(MMCD0_2_MARK, PORT273_FN1, PORT273_IN_PU, + MSEL4CR_MSEL15_0), + PINMUX_DATA(MMCD0_3_MARK, PORT274_FN1, PORT274_IN_PU, + MSEL4CR_MSEL15_0), + PINMUX_DATA(MMCD0_4_MARK, PORT275_FN1, PORT275_IN_PU, + MSEL4CR_MSEL15_0), \ PINMUX_DATA(TS_SPSYNC5_MARK, PORT275_FN3), - PINMUX_DATA(MMCD0_5_MARK, PORT276_FN1, MSEL4CR_MSEL15_0), \ + PINMUX_DATA(MMCD0_5_MARK, PORT276_FN1, PORT276_IN_PU, + MSEL4CR_MSEL15_0), \ PINMUX_DATA(TS_SDAT5_MARK, PORT276_FN3), - PINMUX_DATA(MMCD0_6_MARK, PORT277_FN1, MSEL4CR_MSEL15_0), \ + PINMUX_DATA(MMCD0_6_MARK, PORT277_FN1, PORT277_IN_PU, + MSEL4CR_MSEL15_0), \ PINMUX_DATA(TS_SDEN5_MARK, PORT277_FN3), - PINMUX_DATA(MMCD0_7_MARK, PORT278_FN1, MSEL4CR_MSEL15_0), \ + PINMUX_DATA(MMCD0_7_MARK, PORT278_FN1, PORT278_IN_PU, + MSEL4CR_MSEL15_0), \ PINMUX_DATA(TS_SCK5_MARK, PORT278_FN3), - PINMUX_DATA(MMCCMD0_MARK, PORT279_FN1, MSEL4CR_MSEL15_0), + PINMUX_DATA(MMCCMD0_MARK, PORT279_FN1, PORT279_IN_PU, + MSEL4CR_MSEL15_0), PINMUX_DATA(RESETOUTS__MARK, PORT281_FN1), \ PINMUX_DATA(EXTAL2OUT_MARK, PORT281_FN2), PINMUX_DATA(MCP_WAIT__MCP_FRB_MARK, PORT288_FN1), @@ -1516,16 +1538,29 @@ static pinmux_enum_t pinmux_data[] = { PINMUX_DATA(KEYIN6_PU_MARK, PORT72_FN2, PORT72_IN_PU), PINMUX_DATA(KEYIN7_PU_MARK, PORT73_FN2, PORT73_IN_PU), - PINMUX_DATA(SDHID1_0_PU_MARK, PORT259_IN_PU, PORT259_FN1), - PINMUX_DATA(SDHID1_1_PU_MARK, PORT260_IN_PU, PORT260_FN1), - PINMUX_DATA(SDHID1_2_PU_MARK, PORT261_IN_PU, PORT261_FN1), - PINMUX_DATA(SDHID1_3_PU_MARK, PORT262_IN_PU, PORT262_FN1), - PINMUX_DATA(SDHICMD1_PU_MARK, PORT263_IN_PU, PORT263_FN1), + PINMUX_DATA(SDHICD0_PU_MARK, PORT251_FN1, PORT251_IN_PU), + PINMUX_DATA(SDHID0_0_PU_MARK, PORT252_FN1, PORT252_IN_PU), + PINMUX_DATA(SDHID0_1_PU_MARK, PORT253_FN1, PORT253_IN_PU), + PINMUX_DATA(SDHID0_2_PU_MARK, PORT254_FN1, PORT254_IN_PU), + PINMUX_DATA(SDHID0_3_PU_MARK, PORT255_FN1, PORT255_IN_PU), + PINMUX_DATA(SDHICMD0_PU_MARK, PORT256_FN1, PORT256_IN_PU), + PINMUX_DATA(SDHIWP0_PU_MARK, PORT257_FN1, PORT256_IN_PU), + PINMUX_DATA(SDHID1_0_PU_MARK, PORT259_FN1, PORT259_IN_PU), + PINMUX_DATA(SDHID1_1_PU_MARK, PORT260_FN1, PORT260_IN_PU), + PINMUX_DATA(SDHID1_2_PU_MARK, PORT261_FN1, PORT261_IN_PU), + PINMUX_DATA(SDHID1_3_PU_MARK, PORT262_FN1, PORT262_IN_PU), + PINMUX_DATA(SDHICMD1_PU_MARK, PORT263_FN1, PORT263_IN_PU), + PINMUX_DATA(SDHID2_0_PU_MARK, PORT265_FN1, PORT265_IN_PU), + PINMUX_DATA(SDHID2_1_PU_MARK, PORT266_FN1, PORT266_IN_PU), + PINMUX_DATA(SDHID2_2_PU_MARK, PORT267_FN1, PORT267_IN_PU), + PINMUX_DATA(SDHID2_3_PU_MARK, PORT268_FN1, PORT268_IN_PU), + PINMUX_DATA(SDHICMD2_PU_MARK, PORT269_FN1, PORT269_IN_PU), PINMUX_DATA(MMCCMD0_PU_MARK, PORT279_FN1, PORT279_IN_PU, MSEL4CR_MSEL15_0), - PINMUX_DATA(MMCCMD1_PU_MARK, PORT297_FN2, PORT279_IN_PU, + PINMUX_DATA(MMCCMD1_PU_MARK, PORT297_FN2, PORT297_IN_PU, MSEL4CR_MSEL15_1), + PINMUX_DATA(FSIBISLD_PU_MARK, PORT39_FN1, PORT39_IN_PU), PINMUX_DATA(FSIACK_PU_MARK, PORT49_FN1, PORT49_IN_PU), PINMUX_DATA(FSIAILR_PU_MARK, PORT50_FN5, PORT50_IN_PU), PINMUX_DATA(FSIAIBT_PU_MARK, PORT51_FN5, PORT51_IN_PU), @@ -2181,11 +2216,23 @@ static struct pinmux_gpio pinmux_gpios[] = { GPIO_FN(KEYIN5_PU), GPIO_FN(KEYIN6_PU), GPIO_FN(KEYIN7_PU), + GPIO_FN(SDHICD0_PU), + GPIO_FN(SDHID0_0_PU), + GPIO_FN(SDHID0_1_PU), + GPIO_FN(SDHID0_2_PU), + GPIO_FN(SDHID0_3_PU), + GPIO_FN(SDHICMD0_PU), + GPIO_FN(SDHIWP0_PU), GPIO_FN(SDHID1_0_PU), GPIO_FN(SDHID1_1_PU), GPIO_FN(SDHID1_2_PU), GPIO_FN(SDHID1_3_PU), GPIO_FN(SDHICMD1_PU), + GPIO_FN(SDHID2_0_PU), + GPIO_FN(SDHID2_1_PU), + GPIO_FN(SDHID2_2_PU), + GPIO_FN(SDHID2_3_PU), + GPIO_FN(SDHICMD2_PU), GPIO_FN(MMCCMD0_PU), GPIO_FN(MMCCMD1_PU), GPIO_FN(FSIACK_PU), From 28626632d83696ab3c8f2b9d5d8a658a1787551f Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 18 Aug 2011 05:44:07 +0000 Subject: [PATCH 0069/1596] ARM: mach-shmobile: Kota2 SCIFA2 and SMSC911X support Kota2 base board support including the on-chip SCIFA2 serial console and the on-board SMSC911X ethernet port. The s73a0 SMP bits are also updated to include Kota2. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 7 ++ arch/arm/mach-shmobile/Makefile | 1 + arch/arm/mach-shmobile/board-kota2.c | 168 +++++++++++++++++++++++++++ arch/arm/mach-shmobile/platsmp.c | 10 +- 4 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-shmobile/board-kota2.c diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 0c8f6cf3e948..c1b45342e1fb 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -69,6 +69,11 @@ config MACH_MACKEREL depends on ARCH_SH7372 select ARCH_REQUIRE_GPIOLIB +config MACH_KOTA2 + bool "KOTA2 board" + select ARCH_REQUIRE_GPIOLIB + depends on ARCH_SH73A0 + comment "SH-Mobile System Configuration" menu "Memory configuration" @@ -78,6 +83,7 @@ config MEMORY_START default "0x50000000" if MACH_G3EVM default "0x40000000" if MACH_G4EVM || MACH_AP4EVB || MACH_AG5EVM || \ MACH_MACKEREL + default "0x41000000" if MACH_KOTA2 default "0x00000000" ---help--- Tweak this only when porting to a new machine which does not @@ -89,6 +95,7 @@ config MEMORY_SIZE default "0x08000000" if MACH_G3EVM default "0x08000000" if MACH_G4EVM default "0x20000000" if MACH_AG5EVM + default "0x1e000000" if MACH_KOTA2 default "0x10000000" if MACH_AP4EVB || MACH_MACKEREL default "0x04000000" help diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 612b27000c3e..2aec2f732515 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_MACH_G4EVM) += board-g4evm.o obj-$(CONFIG_MACH_AP4EVB) += board-ap4evb.o obj-$(CONFIG_MACH_AG5EVM) += board-ag5evm.o obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o +obj-$(CONFIG_MACH_KOTA2) += board-kota2.o # Framework support obj-$(CONFIG_SMP) += $(smp-y) diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c new file mode 100644 index 000000000000..4ab05e855077 --- /dev/null +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -0,0 +1,168 @@ +/* + * kota2 board support + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2011 Magnus Damm + * Copyright (C) 2010 Takashi Yoshii + * Copyright (C) 2009 Yoshihiro Shimoda + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct resource smsc9220_resources[] = { + [0] = { + .start = 0x14000000, /* CS5A */ + .end = 0x140000ff, /* A1->A7 */ + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(33), /* PINTA2 @ PORT144 */ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct smsc911x_platform_config smsc9220_platdata = { + .flags = SMSC911X_USE_32BIT, /* 32-bit SW on 16-bit HW bus */ + .phy_interface = PHY_INTERFACE_MODE_MII, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, +}; + +static struct platform_device eth_device = { + .name = "smsc911x", + .id = 0, + .dev = { + .platform_data = &smsc9220_platdata, + }, + .resource = smsc9220_resources, + .num_resources = ARRAY_SIZE(smsc9220_resources), +}; + +static struct platform_device *kota2_devices[] __initdata = { + ð_device, +}; + +static struct map_desc kota2_io_desc[] __initdata = { + /* create a 1:1 entity map for 0xe6xxxxxx + * used by CPGA, INTC and PFC. + */ + { + .virtual = 0xe6000000, + .pfn = __phys_to_pfn(0xe6000000), + .length = 256 << 20, + .type = MT_DEVICE_NONSHARED + }, +}; + +static void __init kota2_map_io(void) +{ + iotable_init(kota2_io_desc, ARRAY_SIZE(kota2_io_desc)); + + /* setup early devices and console here as well */ + sh73a0_add_early_devices(); + shmobile_setup_console(); +} + +#define PINTER0A 0xe69000a0 +#define PINTCR0A 0xe69000b0 + +void __init kota2_init_irq(void) +{ + sh73a0_init_irq(); + + /* setup PINT: enable PINTA2 as active low */ + __raw_writel(1 << 29, PINTER0A); + __raw_writew(2 << 10, PINTCR0A); +} + +static void __init kota2_init(void) +{ + sh73a0_pinmux_init(); + + /* SCIFA2 (UART2) */ + gpio_request(GPIO_FN_SCIFA2_TXD1, NULL); + gpio_request(GPIO_FN_SCIFA2_RXD1, NULL); + gpio_request(GPIO_FN_SCIFA2_RTS1_, NULL); + gpio_request(GPIO_FN_SCIFA2_CTS1_, NULL); + + /* SMSC911X */ + gpio_request(GPIO_FN_D0_NAF0, NULL); + gpio_request(GPIO_FN_D1_NAF1, NULL); + gpio_request(GPIO_FN_D2_NAF2, NULL); + gpio_request(GPIO_FN_D3_NAF3, NULL); + gpio_request(GPIO_FN_D4_NAF4, NULL); + gpio_request(GPIO_FN_D5_NAF5, NULL); + gpio_request(GPIO_FN_D6_NAF6, NULL); + gpio_request(GPIO_FN_D7_NAF7, NULL); + gpio_request(GPIO_FN_D8_NAF8, NULL); + gpio_request(GPIO_FN_D9_NAF9, NULL); + gpio_request(GPIO_FN_D10_NAF10, NULL); + gpio_request(GPIO_FN_D11_NAF11, NULL); + gpio_request(GPIO_FN_D12_NAF12, NULL); + gpio_request(GPIO_FN_D13_NAF13, NULL); + gpio_request(GPIO_FN_D14_NAF14, NULL); + gpio_request(GPIO_FN_D15_NAF15, NULL); + gpio_request(GPIO_FN_CS5A_, NULL); + gpio_request(GPIO_FN_WE0__FWE, NULL); + gpio_request(GPIO_PORT144, NULL); /* PINTA2 */ + gpio_direction_input(GPIO_PORT144); + gpio_request(GPIO_PORT145, NULL); /* RESET */ + gpio_direction_output(GPIO_PORT145, 1); + +#ifdef CONFIG_CACHE_L2X0 + /* Early BRESP enable, Shared attribute override enable, 64K*8way */ + l2x0_init(__io(0xf0100000), 0x40460000, 0x82000fff); +#endif + sh73a0_add_standard_devices(); + platform_add_devices(kota2_devices, ARRAY_SIZE(kota2_devices)); +} + +static void __init kota2_timer_init(void) +{ + sh73a0_clock_init(); + shmobile_timer.init(); + return; +} + +struct sys_timer kota2_timer = { + .init = kota2_timer_init, +}; + +MACHINE_START(KOTA2, "kota2") + .map_io = kota2_map_io, + .init_irq = kota2_init_irq, + .handle_irq = shmobile_handle_irq_gic, + .init_machine = kota2_init, + .timer = &kota2_timer, +MACHINE_END diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c index 66f980625a33..ccd81dac42f8 100644 --- a/arch/arm/mach-shmobile/platsmp.c +++ b/arch/arm/mach-shmobile/platsmp.c @@ -21,9 +21,11 @@ #include #include +#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2()) + static unsigned int __init shmobile_smp_get_core_count(void) { - if (machine_is_ag5evm()) + if (is_sh73a0()) return sh73a0_get_core_count(); return 1; @@ -31,7 +33,7 @@ static unsigned int __init shmobile_smp_get_core_count(void) static void __init shmobile_smp_prepare_cpus(void) { - if (machine_is_ag5evm()) + if (is_sh73a0()) sh73a0_smp_prepare_cpus(); } @@ -39,13 +41,13 @@ void __cpuinit platform_secondary_init(unsigned int cpu) { trace_hardirqs_off(); - if (machine_is_ag5evm()) + if (is_sh73a0()) sh73a0_secondary_init(cpu); } int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { - if (machine_is_ag5evm()) + if (is_sh73a0()) return sh73a0_boot_secondary(cpu); return -ENOSYS; From ef4f994ae11c0a587e2554b1a6b8b0e1dfa07c4e Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 18 Aug 2011 05:44:16 +0000 Subject: [PATCH 0070/1596] ARM: mach-shmobile: Kota2 KEYSC support This patch adds KEYSC support to the Kota2 board. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-kota2.c | 65 ++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index 4ab05e855077..8a6b85a52cb7 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -69,8 +71,52 @@ static struct platform_device eth_device = { .num_resources = ARRAY_SIZE(smsc9220_resources), }; +static struct sh_keysc_info keysc_platdata = { + .mode = SH_KEYSC_MODE_6, + .scan_timing = 3, + .delay = 100, + .keycodes = { + KEY_NUMERIC_STAR, KEY_NUMERIC_0, KEY_NUMERIC_POUND, + 0, 0, 0, 0, 0, + KEY_NUMERIC_7, KEY_NUMERIC_8, KEY_NUMERIC_9, + 0, KEY_DOWN, 0, 0, 0, + KEY_NUMERIC_4, KEY_NUMERIC_5, KEY_NUMERIC_6, + KEY_LEFT, KEY_ENTER, KEY_RIGHT, 0, 0, + KEY_NUMERIC_1, KEY_NUMERIC_2, KEY_NUMERIC_3, + 0, KEY_UP, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }, +}; + +static struct resource keysc_resources[] = { + [0] = { + .name = "KEYSC", + .start = 0xe61b0000, + .end = 0xe61b0098 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(71), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device keysc_device = { + .name = "sh_keysc", + .id = 0, + .num_resources = ARRAY_SIZE(keysc_resources), + .resource = keysc_resources, + .dev = { + .platform_data = &keysc_platdata, + }, +}; + static struct platform_device *kota2_devices[] __initdata = { ð_device, + &keysc_device, }; static struct map_desc kota2_io_desc[] __initdata = { @@ -140,6 +186,25 @@ static void __init kota2_init(void) gpio_request(GPIO_PORT145, NULL); /* RESET */ gpio_direction_output(GPIO_PORT145, 1); + /* KEYSC */ + gpio_request(GPIO_FN_KEYIN0_PU, NULL); + gpio_request(GPIO_FN_KEYIN1_PU, NULL); + gpio_request(GPIO_FN_KEYIN2_PU, NULL); + gpio_request(GPIO_FN_KEYIN3_PU, NULL); + gpio_request(GPIO_FN_KEYIN4_PU, NULL); + gpio_request(GPIO_FN_KEYIN5_PU, NULL); + gpio_request(GPIO_FN_KEYIN6_PU, NULL); + gpio_request(GPIO_FN_KEYIN7_PU, NULL); + gpio_request(GPIO_FN_KEYOUT0, NULL); + gpio_request(GPIO_FN_KEYOUT1, NULL); + gpio_request(GPIO_FN_KEYOUT2, NULL); + gpio_request(GPIO_FN_KEYOUT3, NULL); + gpio_request(GPIO_FN_KEYOUT4, NULL); + gpio_request(GPIO_FN_KEYOUT5, NULL); + gpio_request(GPIO_FN_PORT59_KEYOUT6, NULL); + gpio_request(GPIO_FN_PORT58_KEYOUT7, NULL); + gpio_request(GPIO_FN_KEYOUT8, NULL); + #ifdef CONFIG_CACHE_L2X0 /* Early BRESP enable, Shared attribute override enable, 64K*8way */ l2x0_init(__io(0xf0100000), 0x40460000, 0x82000fff); From 6b7c0ea21226972e08ebb71e134fbebdf7459d1a Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 18 Aug 2011 05:44:25 +0000 Subject: [PATCH 0071/1596] ARM: mach-shmobile: Kota2 GPIO Keys support This patch ties in GPIO Keys support on the Kota2 board. For now the keys are used in polling mode, but after extending the sh73a0 PFC with IRQ support we should be able to switch to the IRQ driven driver. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-kota2.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index 8a6b85a52cb7..849423cddca9 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -114,9 +115,40 @@ static struct platform_device keysc_device = { }, }; +#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 } + +static struct gpio_keys_button gpio_buttons[] = { + GPIO_KEY(KEY_VOLUMEUP, GPIO_PORT56, "+"), /* S2: VOL+ [IRQ9] */ + GPIO_KEY(KEY_VOLUMEDOWN, GPIO_PORT54, "-"), /* S3: VOL- [IRQ10] */ + GPIO_KEY(KEY_MENU, GPIO_PORT27, "Menu"), /* S4: MENU [IRQ30] */ + GPIO_KEY(KEY_HOMEPAGE, GPIO_PORT26, "Home"), /* S5: HOME [IRQ31] */ + GPIO_KEY(KEY_BACK, GPIO_PORT11, "Back"), /* S6: BACK [IRQ0] */ + GPIO_KEY(KEY_PHONE, GPIO_PORT238, "Tel"), /* S7: TEL [IRQ11] */ + GPIO_KEY(KEY_POWER, GPIO_PORT239, "C1"), /* S8: CAM [IRQ13] */ + GPIO_KEY(KEY_MAIL, GPIO_PORT224, "Mail"), /* S9: MAIL [IRQ3] */ + /* Omitted button "C3?": GPIO_PORT223 - S10: CUST [IRQ8] */ + GPIO_KEY(KEY_CAMERA, GPIO_PORT164, "C2"), /* S11: CAM_HALF [IRQ25] */ + /* Omitted button "?": GPIO_PORT152 - S12: CAM_FULL [No IRQ] */ +}; + +static struct gpio_keys_platform_data gpio_key_info = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), + .poll_interval = 250, /* polled for now */ +}; + +static struct platform_device gpio_keys_device = { + .name = "gpio-keys-polled", /* polled for now */ + .id = -1, + .dev = { + .platform_data = &gpio_key_info, + }, +}; + static struct platform_device *kota2_devices[] __initdata = { ð_device, &keysc_device, + &gpio_keys_device, }; static struct map_desc kota2_io_desc[] __initdata = { From ae6e70831805c1d3bb4cdb87a29877b9846d3c15 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 18 Aug 2011 05:44:33 +0000 Subject: [PATCH 0072/1596] ARM: mach-shmobile: Kota2 GPIO LEDs support This patch ties in GPIO LEDs support on the Kota2 board. For now all LEDs are driven by the GPIO LED driver, but in the not so distant future the LEDs hooked up to TPU pin functions will be moved over to the recently posted LED TPU driver. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-kota2.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index 849423cddca9..d46bd9f7cea5 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -145,10 +146,36 @@ static struct platform_device gpio_keys_device = { }, }; +#define GPIO_LED(n, g) { .name = n, .gpio = g } + +static struct gpio_led gpio_leds[] = { + GPIO_LED("V2513", GPIO_PORT153), /* PORT153 [TPU1T02] -> V2513 */ + GPIO_LED("V2514", GPIO_PORT199), /* PORT199 [TPU4TO1] -> V2514 */ + GPIO_LED("V2515", GPIO_PORT197), /* PORT197 [TPU2TO1] -> V2515 */ + GPIO_LED("KEYLED", GPIO_PORT163), /* PORT163 [TPU3TO0] -> KEYLED */ + GPIO_LED("G", GPIO_PORT20), /* PORT20 [GPO0] -> LED7 -> "G" */ + GPIO_LED("H", GPIO_PORT21), /* PORT21 [GPO1] -> LED8 -> "H" */ + GPIO_LED("J", GPIO_PORT22), /* PORT22 [GPO2] -> LED9 -> "J" */ +}; + +static struct gpio_led_platform_data gpio_leds_info = { + .leds = gpio_leds, + .num_leds = ARRAY_SIZE(gpio_leds), +}; + +static struct platform_device gpio_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &gpio_leds_info, + }, +}; + static struct platform_device *kota2_devices[] __initdata = { ð_device, &keysc_device, &gpio_keys_device, + &gpio_leds_device, }; static struct map_desc kota2_io_desc[] __initdata = { From 4e9279452502c043469cf34cd813db83ae87c7d3 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 18 Aug 2011 05:44:42 +0000 Subject: [PATCH 0073/1596] ARM: mach-shmobile: Kota2 MMCIF support Add support for sh73a0 MMCIF hardware block on the Kota2 board. A non-removable eMMC chip is used with 8 data bits on the MMC bus. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-kota2.c | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index d46bd9f7cea5..e1380df01315 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -171,11 +173,44 @@ static struct platform_device gpio_leds_device = { }, }; +static struct resource mmcif_resources[] = { + [0] = { + .name = "MMCIF", + .start = 0xe6bd0000, + .end = 0xe6bd00ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(140), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = gic_spi(141), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct sh_mmcif_plat_data mmcif_info = { + .ocr = MMC_VDD_165_195, + .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE, +}; + +static struct platform_device mmcif_device = { + .name = "sh_mmcif", + .id = 0, + .dev = { + .platform_data = &mmcif_info, + }, + .num_resources = ARRAY_SIZE(mmcif_resources), + .resource = mmcif_resources, +}; + static struct platform_device *kota2_devices[] __initdata = { ð_device, &keysc_device, &gpio_keys_device, &gpio_leds_device, + &mmcif_device, }; static struct map_desc kota2_io_desc[] __initdata = { @@ -264,6 +299,20 @@ static void __init kota2_init(void) gpio_request(GPIO_FN_PORT58_KEYOUT7, NULL); gpio_request(GPIO_FN_KEYOUT8, NULL); + /* MMCIF */ + gpio_request(GPIO_FN_MMCCLK0, NULL); + gpio_request(GPIO_FN_MMCD0_0, NULL); + gpio_request(GPIO_FN_MMCD0_1, NULL); + gpio_request(GPIO_FN_MMCD0_2, NULL); + gpio_request(GPIO_FN_MMCD0_3, NULL); + gpio_request(GPIO_FN_MMCD0_4, NULL); + gpio_request(GPIO_FN_MMCD0_5, NULL); + gpio_request(GPIO_FN_MMCD0_6, NULL); + gpio_request(GPIO_FN_MMCD0_7, NULL); + gpio_request(GPIO_FN_MMCCMD0, NULL); + gpio_request(GPIO_PORT208, NULL); /* Reset */ + gpio_direction_output(GPIO_PORT208, 1); + #ifdef CONFIG_CACHE_L2X0 /* Early BRESP enable, Shared attribute override enable, 64K*8way */ l2x0_init(__io(0xf0100000), 0x40460000, 0x82000fff); From 9e9a892417317c3c7fc98f9a87f51c0e7b013b36 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 18 Aug 2011 05:44:51 +0000 Subject: [PATCH 0074/1596] ARM: mach-shmobile: Kota2 SCIFA4 and SCIFB support Add SCIFA4 and SCIFB support to the Kota2 board. Only pins are configured since the SCIF platform devices are already present in the sh73a0 code. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-kota2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index e1380df01315..0dbee59bc6d9 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -256,6 +256,12 @@ static void __init kota2_init(void) gpio_request(GPIO_FN_SCIFA2_RTS1_, NULL); gpio_request(GPIO_FN_SCIFA2_CTS1_, NULL); + /* SCIFA4 (UART1) */ + gpio_request(GPIO_FN_SCIFA4_TXD, NULL); + gpio_request(GPIO_FN_SCIFA4_RXD, NULL); + gpio_request(GPIO_FN_SCIFA4_RTS_, NULL); + gpio_request(GPIO_FN_SCIFA4_CTS_, NULL); + /* SMSC911X */ gpio_request(GPIO_FN_D0_NAF0, NULL); gpio_request(GPIO_FN_D1_NAF1, NULL); @@ -313,6 +319,13 @@ static void __init kota2_init(void) gpio_request(GPIO_PORT208, NULL); /* Reset */ gpio_direction_output(GPIO_PORT208, 1); + /* SCIFB (BT) */ + gpio_request(GPIO_FN_PORT159_SCIFB_SCK, NULL); + gpio_request(GPIO_FN_PORT160_SCIFB_TXD, NULL); + gpio_request(GPIO_FN_PORT161_SCIFB_CTS_, NULL); + gpio_request(GPIO_FN_PORT162_SCIFB_RXD, NULL); + gpio_request(GPIO_FN_PORT163_SCIFB_RTS_, NULL); + #ifdef CONFIG_CACHE_L2X0 /* Early BRESP enable, Shared attribute override enable, 64K*8way */ l2x0_init(__io(0xf0100000), 0x40460000, 0x82000fff); From 8722c996d61948a57ada840350b0383f6879bcaa Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 18 Aug 2011 05:45:00 +0000 Subject: [PATCH 0075/1596] ARM: mach-shmobile: Kota2 SDHI0 and SDHI1 support Add SDHI0 and SDHI1 support to the Kota2 board. SDHI0 is hooked up to a microSD card slot and SDHI1 to a wireless module that also connects to SCIFB. This depends on the recently merged code for TMIO_MMC_HAS_IDLE_WAIT together with PFC support for pull-ups on SDHI0 and SDHI1. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-kota2.c | 93 ++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index 0dbee59bc6d9..adc73122bf20 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -205,12 +207,86 @@ static struct platform_device mmcif_device = { .resource = mmcif_resources, }; +static struct sh_mobile_sdhi_info sdhi0_info = { + .tmio_caps = MMC_CAP_SD_HIGHSPEED, + .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT, +}; + +static struct resource sdhi0_resources[] = { + [0] = { + .name = "SDHI0", + .start = 0xee100000, + .end = 0xee1000ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(83), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = gic_spi(84), + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = gic_spi(85), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi0_device = { + .name = "sh_mobile_sdhi", + .id = 0, + .num_resources = ARRAY_SIZE(sdhi0_resources), + .resource = sdhi0_resources, + .dev = { + .platform_data = &sdhi0_info, + }, +}; + +static struct sh_mobile_sdhi_info sdhi1_info = { + .tmio_caps = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ, + .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT, +}; + +static struct resource sdhi1_resources[] = { + [0] = { + .name = "SDHI1", + .start = 0xee120000, + .end = 0xee1200ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(87), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = gic_spi(88), + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = gic_spi(89), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi1_device = { + .name = "sh_mobile_sdhi", + .id = 1, + .num_resources = ARRAY_SIZE(sdhi1_resources), + .resource = sdhi1_resources, + .dev = { + .platform_data = &sdhi1_info, + }, +}; + static struct platform_device *kota2_devices[] __initdata = { ð_device, &keysc_device, &gpio_keys_device, &gpio_leds_device, &mmcif_device, + &sdhi0_device, + &sdhi1_device, }; static struct map_desc kota2_io_desc[] __initdata = { @@ -319,6 +395,15 @@ static void __init kota2_init(void) gpio_request(GPIO_PORT208, NULL); /* Reset */ gpio_direction_output(GPIO_PORT208, 1); + /* SDHI0 (microSD) */ + gpio_request(GPIO_FN_SDHICD0_PU, NULL); + gpio_request(GPIO_FN_SDHICMD0_PU, NULL); + gpio_request(GPIO_FN_SDHICLK0, NULL); + gpio_request(GPIO_FN_SDHID0_3_PU, NULL); + gpio_request(GPIO_FN_SDHID0_2_PU, NULL); + gpio_request(GPIO_FN_SDHID0_1_PU, NULL); + gpio_request(GPIO_FN_SDHID0_0_PU, NULL); + /* SCIFB (BT) */ gpio_request(GPIO_FN_PORT159_SCIFB_SCK, NULL); gpio_request(GPIO_FN_PORT160_SCIFB_TXD, NULL); @@ -326,6 +411,14 @@ static void __init kota2_init(void) gpio_request(GPIO_FN_PORT162_SCIFB_RXD, NULL); gpio_request(GPIO_FN_PORT163_SCIFB_RTS_, NULL); + /* SDHI1 (BCM4330) */ + gpio_request(GPIO_FN_SDHICLK1, NULL); + gpio_request(GPIO_FN_SDHICMD1_PU, NULL); + gpio_request(GPIO_FN_SDHID1_3_PU, NULL); + gpio_request(GPIO_FN_SDHID1_2_PU, NULL); + gpio_request(GPIO_FN_SDHID1_1_PU, NULL); + gpio_request(GPIO_FN_SDHID1_0_PU, NULL); + #ifdef CONFIG_CACHE_L2X0 /* Early BRESP enable, Shared attribute override enable, 64K*8way */ l2x0_init(__io(0xf0100000), 0x40460000, 0x82000fff); From 981ed70d8e4faf3689dbf3c48868a31d5b004d7a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Aug 2011 16:50:51 +0200 Subject: [PATCH 0076/1596] dmatest: make dmatest threads freezable Making dmatest threads freezable allows its use for system PM testing. Signed-off-by: Guennadi Liakhovetski Acked-by: Dan Williams Signed-off-by: Vinod Koul --- drivers/dma/dmatest.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index accc18441b16..eb1d8641cf5c 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,7 @@ static int dmatest_func(void *data) int i; thread_name = current->comm; + set_freezable_with_signal(); ret = -ENOMEM; @@ -305,7 +307,8 @@ static int dmatest_func(void *data) dma_addr_t dma_srcs[src_cnt]; dma_addr_t dma_dsts[dst_cnt]; struct completion cmp; - unsigned long tmo = msecs_to_jiffies(timeout); + unsigned long start, tmo, end = 0 /* compiler... */; + bool reload = true; u8 align = 0; total_tests++; @@ -404,7 +407,17 @@ static int dmatest_func(void *data) } dma_async_issue_pending(chan); - tmo = wait_for_completion_timeout(&cmp, tmo); + do { + start = jiffies; + if (reload) + end = start + msecs_to_jiffies(timeout); + else if (end <= start) + end = start + 1; + tmo = wait_for_completion_interruptible_timeout(&cmp, + end - start); + reload = try_to_freeze(); + } while (tmo == -ERESTARTSYS); + status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); if (tmo == 0) { From 73eab978ad6934499b83ecc920d470fe99c5e54d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 25 Aug 2011 11:03:35 +0200 Subject: [PATCH 0077/1596] dmaengine i.MX SDMA: lock channel 0 channel0 of the sdma engine is the configuration channel. It is a shared resource and thus must be protected by a mutex. Signed-off-by: Sascha Hauer Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 7bd7e98548cd..f50c87c303dd 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -318,6 +318,7 @@ struct sdma_engine { dma_addr_t context_phys; struct dma_device dma_device; struct clk *clk; + struct mutex channel_0_lock; struct sdma_script_start_addrs *script_addrs; }; @@ -415,11 +416,15 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, dma_addr_t buf_phys; int ret; + mutex_lock(&sdma->channel_0_lock); + buf_virt = dma_alloc_coherent(NULL, size, &buf_phys, GFP_KERNEL); - if (!buf_virt) - return -ENOMEM; + if (!buf_virt) { + ret = -ENOMEM; + goto err_out; + } bd0->mode.command = C0_SETPM; bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; @@ -433,6 +438,9 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, dma_free_coherent(NULL, size, buf_virt, buf_phys); +err_out: + mutex_unlock(&sdma->channel_0_lock); + return ret; } @@ -656,6 +664,8 @@ static int sdma_load_context(struct sdma_channel *sdmac) dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0); dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1); + mutex_lock(&sdma->channel_0_lock); + memset(context, 0, sizeof(*context)); context->channel_state.pc = load_address; @@ -676,6 +686,8 @@ static int sdma_load_context(struct sdma_channel *sdmac) ret = sdma_run_channel(&sdma->channel[0]); + mutex_unlock(&sdma->channel_0_lock); + return ret; } @@ -1274,6 +1286,8 @@ static int __init sdma_probe(struct platform_device *pdev) if (!sdma) return -ENOMEM; + mutex_init(&sdma->channel_0_lock); + sdma->dev = &pdev->dev; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); From 36e2f21ab481b3d6bd31b99e1de669fbbac4bd0e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 25 Aug 2011 11:03:36 +0200 Subject: [PATCH 0078/1596] dmaengine i.MX SDMA: set firmware scripts addresses to negative value initially If we do not have a firmare script for a given transfer, the setup of this channel must fail. For this the script addresses have to be < 0 initially, not 0. Signed-off-by: Sascha Hauer Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f50c87c303dd..8abf8c190aad 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1281,6 +1281,7 @@ static int __init sdma_probe(struct platform_device *pdev) struct sdma_platform_data *pdata = pdev->dev.platform_data; int i; struct sdma_engine *sdma; + s32 *saddr_arr; sdma = kzalloc(sizeof(*sdma), GFP_KERNEL); if (!sdma) @@ -1324,6 +1325,11 @@ static int __init sdma_probe(struct platform_device *pdev) goto err_alloc; } + /* initially no scripts available */ + saddr_arr = (s32 *)sdma->script_addrs; + for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) + saddr_arr[i] = -EINVAL; + if (of_id) pdev->id_entry = of_id->data; sdma->devtype = pdev->id_entry->driver_data; From 7b4b88e067d37cbbafd856121767f7e154294eb2 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 25 Aug 2011 11:03:37 +0200 Subject: [PATCH 0079/1596] dmaengine i.MX SDMA: use request_firmware_nowait The firmware blob may not be available when the driver probes. Instead of blocking the whole kernel use request_firmware_nowait() and continue without firmware. The ROM scripts can already be used then if available. For the devicetree case the ROM scripts are not available, still the probe function should not block. The driver will be unusable in this case, but we have no way of detecting this properly. The configuration of the dma channels will fail, so nothing bad should happen. Signed-off-by: Sascha Hauer Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 8abf8c190aad..b5cc27dc9a51 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1143,18 +1143,17 @@ static void sdma_add_scripts(struct sdma_engine *sdma, saddr_arr[i] = addr_arr[i]; } -static int __init sdma_get_firmware(struct sdma_engine *sdma, - const char *fw_name) +static void sdma_load_firmware(const struct firmware *fw, void *context) { - const struct firmware *fw; + struct sdma_engine *sdma = context; const struct sdma_firmware_header *header; - int ret; const struct sdma_script_start_addrs *addr; unsigned short *ram_code; - ret = request_firmware(&fw, fw_name, sdma->dev); - if (ret) - return ret; + if (!fw) { + dev_err(sdma->dev, "firmware not found\n"); + return; + } if (fw->size < sizeof(*header)) goto err_firmware; @@ -1184,6 +1183,16 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma, err_firmware: release_firmware(fw); +} + +static int __init sdma_get_firmware(struct sdma_engine *sdma, + const char *fw_name) +{ + int ret; + + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, fw_name, sdma->dev, + GFP_KERNEL, sdma, sdma_load_firmware); return ret; } From 0c54781bc5aaec1e23bc50a4ef757b8e8bfc693b Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 17:55:54 +0000 Subject: [PATCH 0080/1596] DocBook/drm: Clean up code comment Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index b9079386040d..4ddc99928668 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -88,8 +88,8 @@ static struct drm_driver driver = { - /* don't use mtrr's here, the Xserver or user space app should - * deal with them for intel hardware. + /* Don't use MTRRs here; the Xserver or userspace app should + * deal with them for Intel hardware. */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ce045a8cf82c..acf4ea84c801 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -785,8 +785,8 @@ static struct vm_operations_struct i915_gem_vm_ops = { }; static struct drm_driver driver = { - /* don't use mtrr's here, the Xserver or user space app should - * deal with them for intel hardware. + /* Don't use MTRRs here; the Xserver or userspace app should + * deal with them for Intel hardware. */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ From 2c267e9e016da3e19a95261875a5f3b19dd6e9f6 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:10:12 +0000 Subject: [PATCH 0081/1596] DocBook/drm: Use a semicolon Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 4ddc99928668..aa13e0883510 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -154,8 +154,8 @@ In the example above, taken from the i915 DRM driver, the driver - sets several flags indicating what core features it supports. - We go over the individual callbacks in later sections. Since + sets several flags indicating what core features it supports; + we go over the individual callbacks in later sections. Since flags indicate which features your driver supports to the DRM core, you need to set most of them prior to calling drm_init(). Some, like DRIVER_MODESET can be set later based on user supplied parameters, @@ -647,8 +647,8 @@ void intel_crt_init(struct drm_device *dev) Memory management - The memory manager lies at the heart of many DRM operations, and - is also required to support advanced client features like OpenGL + The memory manager lies at the heart of many DRM operations; it + is required to support advanced client features like OpenGL pbuffers. The DRM currently contains two memory managers, TTM and GEM. From 02391f1fe7b4e5434e4c558dcae99b9368c84bf3 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:20:54 +0000 Subject: [PATCH 0082/1596] DocBook/drm: a -> an Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index aa13e0883510..5b815b83c30b 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -203,7 +203,7 @@ DRIVER_HAVE_IRQDRIVER_IRQ_SHARED - DRIVER_HAVE_IRQ indicates whether the driver has a IRQ + DRIVER_HAVE_IRQ indicates whether the driver has an IRQ handler, DRIVER_IRQ_SHARED indicates whether the device & handler support shared IRQs (note that this is required of PCI drivers). From b1f95bdc1eb10e3d3c8a85b2f0bc08fa6c08ae5d Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:21:29 +0000 Subject: [PATCH 0083/1596] DocBook/drm: , -> . Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 5b815b83c30b..a0f0f984f04f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -204,7 +204,7 @@ DRIVER_HAVE_IRQ indicates whether the driver has an IRQ - handler, DRIVER_IRQ_SHARED indicates whether the device & + handler. DRIVER_IRQ_SHARED indicates whether the device & handler support shared IRQs (note that this is required of PCI drivers). From 80c84e6f3c2c707ccb5d7b500e25bda69f0e1895 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:23:21 +0000 Subject: [PATCH 0084/1596] DocBook/drm: Move `should be set' to the beginning of the sentence Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index a0f0f984f04f..42368f4f7bab 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -214,8 +214,8 @@ DRIVER_DMA_QUEUE - If the driver queues DMA requests and completes them - asynchronously, this flag should be set. Deprecated. + Should be set if the driver queues DMA requests and completes them + asynchronously. Deprecated. From 58f1d652def02db0bdcdf03d01f3483fc18ec392 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:31:42 +0000 Subject: [PATCH 0085/1596] DocBook/drm: Clean up `pre-memory management aware' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 42368f4f7bab..e9242c09ac54 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -273,7 +273,7 @@ conflict with DRM client requirements. For instance, if user level mode setting drivers are in use, it would be problematic to perform output discovery & configuration at load time. - Likewise, if pre-memory management aware user level drivers are + Likewise, if user-level drivers unaware of memory management are in use, memory management and command buffer setup may need to be omitted. These requirements are driver specific, and care needs to be taken to keep both old and new applications and From 75aa9df5a2bf2ae90a1f0f6f283278f634ca4233 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:34:49 +0000 Subject: [PATCH 0086/1596] DocBook/drm: Rearrange wording to make more sense Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index e9242c09ac54..eb28cc02d41b 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -281,9 +281,9 @@ module parameter to control whether advanced features are enabled at load time or in legacy fashion. If compatibility is a concern (e.g. with drivers converted over to the new interfaces - from the old ones), care must be taken to prevent incompatible - device initialization and control with the currently active - userspace drivers. + from the old ones), care must be taken to prevent device + initialization and control that is incompatible with + currently active userspace drivers. From 6e375f44b6073dd320895753ff05cbfd3f410f66 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:37:05 +0000 Subject: [PATCH 0087/1596] DocBook/drm: Replace the paragraph's first sentence with its last sentence Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index eb28cc02d41b..9eda9b6df51d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -269,8 +269,10 @@ initial output configuration. - Note that the tasks performed at driver load time must not - conflict with DRM client requirements. For instance, if user + If compatibility is a concern (e.g. with drivers converted over + to the new interfaces from the old ones), care must be taken to + prevent device initialization and control that is incompatible with + currently active userspace drivers. For instance, if user level mode setting drivers are in use, it would be problematic to perform output discovery & configuration at load time. Likewise, if user-level drivers unaware of memory management are @@ -279,11 +281,7 @@ needs to be taken to keep both old and new applications and libraries working. The i915 driver supports the "modeset" module parameter to control whether advanced features are - enabled at load time or in legacy fashion. If compatibility is - a concern (e.g. with drivers converted over to the new interfaces - from the old ones), care must be taken to prevent device - initialization and control that is incompatible with - currently active userspace drivers. + enabled at load time or in legacy fashion. From 06fa7b8066d4dc3f6c9d4c4bf34f385d5a823f13 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:40:55 +0000 Subject: [PATCH 0088/1596] DocBook/drm: Better wording Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 9eda9b6df51d..b4196c1a239d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -292,8 +292,8 @@ information, like register offsets, command buffer status, register state for suspend/resume, etc. At load time, a driver may simply allocate one and set drm_device.dev_priv - appropriately; at unload the driver can free it and set - drm_device.dev_priv to NULL. + appropriately; it should be freed and drm_device.dev_priv set + to NULL when the driver is unloaded. The DRM supports several counters which may be used for rough From 57a15fd663d6680dc100a537f0ed328993c33af2 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:42:36 +0000 Subject: [PATCH 0089/1596] DocBook/drm: Clearer wording with `for consumption by' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index b4196c1a239d..33290e3e3ffa 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -305,8 +305,8 @@ These interfaces are deprecated and should not be used. If performance monitoring is desired, the developer should investigate and potentially enhance the kernel perf and tracing infrastructure to export - GPU related performance information to performance monitoring - tools and applications. + GPU related performance information for consumption by performance + monitoring tools and applications. From 8814630f0b59421e558f4403b79f5dc3a025a386 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:46:10 +0000 Subject: [PATCH 0090/1596] DocBook/drm: Insert missing `that' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 33290e3e3ffa..25e0f460a973 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -321,10 +321,10 @@ Finding & mapping resources is fairly straightforward. The DRM wrapper functions, drm_get_resource_start() and - drm_get_resource_len() may be used to find BARs on the given + drm_get_resource_len(), may be used to find BARs on the given drm_device struct. Once those values have been retrieved, the driver load function can call drm_addmap() to create a new - mapping for the BAR in question. Note you probably want a + mapping for the BAR in question. Note that you probably want a drm_local_map_t in your driver private structure to track any mappings you create. From f07faf693c59b449b6637ea056e5826c85dcd265 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:48:15 +0000 Subject: [PATCH 0091/1596] DocBook/drm: Insert missing `an' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 25e0f460a973..1b2e3c37e377 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -342,7 +342,7 @@ DRM_WRITEn() macros to access the registers on your device, or use driver specific versions to offset into your MMIO space relative to a driver specific base pointer (see I915_READ for - example). + an example). If your device supports interrupt generation, you may want to From 5b658bf2bf9e47f9a67cd26b1c69e4441eaf04fc Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:49:11 +0000 Subject: [PATCH 0092/1596] DocBook/drm: `setup' is the noun; `to set up' is the verb Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 1b2e3c37e377..d2f1ddaa3ca0 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -346,7 +346,7 @@ If your device supports interrupt generation, you may want to - setup an interrupt handler at driver load time as well. This + set up an interrupt handler at driver load time as well. This is done using the drm_irq_install() function. If your device supports vertical blank interrupts, it should call drm_vblank_init() to initialize the core vblank handling code before From bb49a6a1f3303f9cf23a19f403c9b90cdff0e7da Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:50:14 +0000 Subject: [PATCH 0093/1596] DocBook/drm: `at driver load time' -> `when the driver is loaded' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index d2f1ddaa3ca0..7001937f6b7d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -346,7 +346,7 @@ If your device supports interrupt generation, you may want to - set up an interrupt handler at driver load time as well. This + set up an interrupt handler when the driver is loaded. This is done using the drm_irq_install() function. If your device supports vertical blank interrupts, it should call drm_vblank_init() to initialize the core vblank handling code before From 9c2416adac986d7d90814d7985a0ea80ebea416f Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:56:12 +0000 Subject: [PATCH 0094/1596] DocBook/drm: Use the passive voice Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 7001937f6b7d..03321ebaf4a7 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -369,9 +369,9 @@ using the pci_map_rom() call, a convenience function that takes care of mapping the actual ROM, whether it has been shadowed into memory (typically at address 0xc0000) or exists - on the PCI device in the ROM BAR. Note that once you've - mapped the ROM and extracted any necessary information, be - sure to unmap it; on many devices the ROM address decoder is + on the PCI device in the ROM BAR. Note that after the ROM + has been mapped and any necessary information has been extracted, + it should be unmapped; on many devices the ROM address decoder is shared with other BARs, so leaving it mapped can cause undesired behavior like hangs or memory corruption. From 118bdd70bdd73b08dcc3920fa30a21be5bbbffae Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:57:04 +0000 Subject: [PATCH 0095/1596] DocBook/drm: Offset modifiers with commas Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 03321ebaf4a7..ce145babef6e 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -371,7 +371,7 @@ shadowed into memory (typically at address 0xc0000) or exists on the PCI device in the ROM BAR. Note that after the ROM has been mapped and any necessary information has been extracted, - it should be unmapped; on many devices the ROM address decoder is + it should be unmapped; on many devices, the ROM address decoder is shared with other BARs, so leaving it mapped can cause undesired behavior like hangs or memory corruption. @@ -440,7 +440,7 @@ and its size should be sizeof(struct ttm_bo_global). Again, driver specific init and release functions may be provided, likely eventually calling ttm_bo_global_init and - ttm_bo_global_release, respectively. Also like the previous + ttm_bo_global_release, respectively. Also, like the previous object, ttm_global_item_ref is used to create an initial reference count for the TTM, which will call your initialization function. @@ -613,7 +613,7 @@ void intel_crt_init(struct drm_device *dev) DRM_IOCTL_MODESET_CTL should be called by application level - drivers before and after mode setting, since on many devices the + drivers before and after mode setting, since on many devices, the vertical blank counter is reset at that time. Internally, the DRM snapshots the last vblank count when the ioctl is called with the _DRM_PRE_MODESET command so that the counter won't go @@ -696,7 +696,7 @@ void intel_crt_init(struct drm_device *dev) set domain function, which evaluates an object's current domain and performs any necessary flushing or synchronization to put the object into the desired coherency domain (note that the object may be busy, - i.e. an active render target; in that case the set domain function + i.e. an active render target; in that case, the set domain function blocks the client and waits for rendering to complete before performing any necessary flushing operations). From 8d36ffae67d89a86e37e7745503743fec1ac695c Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:57:37 +0000 Subject: [PATCH 0096/1596] DocBook/drm: can -> could Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index ce145babef6e..60ddf4be11c7 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -372,7 +372,7 @@ on the PCI device in the ROM BAR. Note that after the ROM has been mapped and any necessary information has been extracted, it should be unmapped; on many devices, the ROM address decoder is - shared with other BARs, so leaving it mapped can cause + shared with other BARs, so leaving it mapped could cause undesired behavior like hangs or memory corruption. From eb2b8d4273fb8b73821ca8dbc9c0de10e9879833 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 18:58:42 +0000 Subject: [PATCH 0097/1596] DocBook/drm: , -> : Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 60ddf4be11c7..953c4cb726bb 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -389,7 +389,7 @@ If your driver supports memory management (it should!), you need to set that up at load time as well. How you initialize - it depends on which memory manager you're using, TTM or GEM. + it depends on which memory manager you're using: TTM or GEM. TTM initialization @@ -647,7 +647,7 @@ void intel_crt_init(struct drm_device *dev) The memory manager lies at the heart of many DRM operations; it is required to support advanced client features like OpenGL - pbuffers. The DRM currently contains two memory managers, TTM + pbuffers. The DRM currently contains two memory managers: TTM and GEM. From 005d7f4a01d3c755c3abab38b7e380f0bbff475d Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:02:52 +0000 Subject: [PATCH 0098/1596] DocBook/drm: Insert missing comma Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 953c4cb726bb..230c738c22f0 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -429,7 +429,7 @@ object should be sizeof(struct ttm_mem_global), and the init and release hooks should point at your driver specific init and release routines, which probably eventually call - ttm_mem_global_init and ttm_mem_global_release respectively. + ttm_mem_global_init and ttm_mem_global_release, respectively. Once your global TTM accounting structure is set up and initialized @@ -499,8 +499,8 @@ Output discovery and initialization - Several core functions exist to create CRTCs, encoders and - connectors, namely drm_crtc_init(), drm_connector_init() and + Several core functions exist to create CRTCs, encoders, and + connectors, namely drm_crtc_init(), drm_connector_init(), and drm_encoder_init(), along with several "helper" functions to perform common tasks. @@ -578,7 +578,7 @@ void intel_crt_init(struct drm_device *dev) - For each encoder, CRTC and connector, several functions must + For each encoder, CRTC, and connector, several functions must be provided, depending on the object type. Encoder objects need to provide a DPMS (basically on/off) function, mode fixup (for converting requested modes into native hardware timings), @@ -727,7 +727,7 @@ void intel_crt_init(struct drm_device *dev) Output management At the core of the DRM output management code is a set of - structures representing CRTCs, encoders and connectors. + structures representing CRTCs, encoders, and connectors. A CRTC is an abstraction representing a part of the chip that From 1c86de2216f678bfb6e2472af6e5c25b0df8d91f Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:14:26 +0000 Subject: [PATCH 0099/1596] DocBook/drm: Remove parentheses and unnecessary repetition Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 230c738c22f0..6b2a80369f6b 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -433,8 +433,8 @@ Once your global TTM accounting structure is set up and initialized - (done by calling ttm_global_item_ref on the global object you - just created), you need to create a buffer object TTM to + by calling ttm_global_item_ref on it, + you need to create a buffer object TTM to provide a pool for buffer object allocation by clients and the kernel itself. The type of this object should be TTM_GLOBAL_TTM_BO, and its size should be sizeof(struct ttm_bo_global). Again, From ae63d793a43888eeb1c16422252d987aa37ab96c Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:19:18 +0000 Subject: [PATCH 0100/1596] DocBook/drm: Insert `()' after function name Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 6b2a80369f6b..6977cd91779c 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -433,15 +433,15 @@ Once your global TTM accounting structure is set up and initialized - by calling ttm_global_item_ref on it, + by calling ttm_global_item_ref() on it, you need to create a buffer object TTM to provide a pool for buffer object allocation by clients and the kernel itself. The type of this object should be TTM_GLOBAL_TTM_BO, and its size should be sizeof(struct ttm_bo_global). Again, driver specific init and release functions may be provided, - likely eventually calling ttm_bo_global_init and - ttm_bo_global_release, respectively. Also, like the previous - object, ttm_global_item_ref is used to create an initial reference + likely eventually calling ttm_bo_global_init() and + ttm_bo_global_release(), respectively. Also, like the previous + object, ttm_global_item_ref() is used to create an initial reference count for the TTM, which will call your initialization function. From 049cc903e714a27805eae0c34a4c34902a385032 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:21:17 +0000 Subject: [PATCH 0101/1596] DocBook/drm: Streamline wording of GEM initialization Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 6977cd91779c..7c11d790f749 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -451,7 +451,7 @@ GEM is an alternative to TTM, designed specifically for UMA devices. It has simpler initialization and execution requirements than TTM, but has no VRAM management capability. Core GEM - initialization is comprised of a basic drm_mm_init call to create + is initialized by calling drm_mm_init() to create a GTT DRM MM object, which provides an address space pool for object allocation. In a KMS configuration, the driver needs to allocate and initialize a command ring buffer following From 482b2ad8e488e609bb3bb408a8e9ca17b73b17c6 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:37:24 +0000 Subject: [PATCH 0102/1596] DocBook/drm: basic -> core Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 7c11d790f749..d385e902f5ff 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -455,7 +455,7 @@ a GTT DRM MM object, which provides an address space pool for object allocation. In a KMS configuration, the driver needs to allocate and initialize a command ring buffer following - basic GEM initialization. Most UMA devices have a so-called + core GEM initialization. Most UMA devices have a so-called "stolen" memory region, which provides space for the initial framebuffer and large, contiguous memory regions required by the device. This space is not typically managed by GEM, and must From 54f2cb8fc930e08fd6156519b28c45d576615f82 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:41:37 +0000 Subject: [PATCH 0103/1596] DocBook/drm: Use a singular subject for grammatical cleanliness Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index d385e902f5ff..3470c6b2f843 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -455,7 +455,7 @@ a GTT DRM MM object, which provides an address space pool for object allocation. In a KMS configuration, the driver needs to allocate and initialize a command ring buffer following - core GEM initialization. Most UMA devices have a so-called + core GEM initialization. A UMA device usually has a so-called "stolen" memory region, which provides space for the initial framebuffer and large, contiguous memory regions required by the device. This space is not typically managed by GEM, and must @@ -635,10 +635,10 @@ void intel_crt_init(struct drm_device *dev) a client calls the vblank wait ioctl above. - Devices that don't provide a count register may simply use an + A device that doesn't provide a count register may simply use an internal atomic counter incremented on every vertical blank - interrupt, and can make their enable and disable vblank - functions into no-ops. + interrupt (and then treat the enable_vblank() and disable_vblank() + callbacks as no-ops). From 9029bd7a42e3c32783866630ee3eb6b82e273544 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:42:20 +0000 Subject: [PATCH 0104/1596] DocBook/drm: The word `so-called'; I do not think it connotes what you think it connotes From Webster's Revised Unabridged Dictionary (1913) [web1913]: So-called \So"-called`\, a. So named; called by such a name (but perhaps called thus with doubtful propriety). From WordNet (r) 2.0 [wn]: so-called adj : doubtful or suspect; "these so-called experts are no help" [syn: {alleged(a)}, {supposed}] My strong conviction is that widespread use of 'so gennant' or 'sogennant' in German has led to the creeping misuse of 'so-called' in English (especially through technical writings). In English, it would be better to use: what is called or a better translation of 'so gennant': so named Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 3470c6b2f843..66a114a05c6f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -455,7 +455,7 @@ a GTT DRM MM object, which provides an address space pool for object allocation. In a KMS configuration, the driver needs to allocate and initialize a command ring buffer following - core GEM initialization. A UMA device usually has a so-called + core GEM initialization. A UMA device usually has what is called a "stolen" memory region, which provides space for the initial framebuffer and large, contiguous memory regions required by the device. This space is not typically managed by GEM, and must From 1dbd39c3ea3967c41a09e81c826499f7ae9c8180 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:48:32 +0000 Subject: [PATCH 0105/1596] DocBook/drm: Insert `it' for smooth reading Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 66a114a05c6f..15541b1fc052 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -458,7 +458,7 @@ core GEM initialization. A UMA device usually has what is called a "stolen" memory region, which provides space for the initial framebuffer and large, contiguous memory regions required by the - device. This space is not typically managed by GEM, and must + device. This space is not typically managed by GEM, and it must be initialized separately into its own DRM MM object. From 3bf7df615612671271512aada7d83285f3fa731b Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 19:49:10 +0000 Subject: [PATCH 0106/1596] DocBook/drm: Remove redundancy Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 15541b1fc052..c24f50ce7862 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -462,8 +462,7 @@ be initialized separately into its own DRM MM object. - Initialization is driver specific, and depends on - the architecture of the device. In the case of Intel + Initialization is driver specific. In the case of Intel integrated graphics chips like 965GM, GEM initialization can be done by calling the internal GEM init function, i915_gem_do_init(). Since the 965GM is a UMA device From 327d6fb962f227a31d4b03869774287efca49c50 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 20:18:14 +0000 Subject: [PATCH 0107/1596] DocBook/drm: Clarify `final initialization' via better formatting Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index c24f50ce7862..1bbeea72a01f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -490,10 +490,19 @@ Output configuration - The final initialization task is output configuration. This involves - finding and initializing the CRTCs, encoders and connectors - for your device, creating an initial configuration and - registering a framebuffer console driver. + The final initialization task is output configuration. This involves: + + + Finding and initializing the CRTCs, encoders, and connectors + for the device. + + + Creating an initial configuration. + + + Registering a framebuffer console driver. + + Output discovery and initialization From 8a9ba910ac3962e5adb4ce1f086adf1e21fa04d1 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 20:21:22 +0000 Subject: [PATCH 0108/1596] DocBook/drm: Use a colon Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 1bbeea72a01f..790e634e5635 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -508,7 +508,7 @@ Output discovery and initialization Several core functions exist to create CRTCs, encoders, and - connectors, namely drm_crtc_init(), drm_connector_init(), and + connectors, namely: drm_crtc_init(), drm_connector_init(), and drm_encoder_init(), along with several "helper" functions to perform common tasks. From 896ee65fb646f9a98243a9f69e5904dff394c78a Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 20:26:17 +0000 Subject: [PATCH 0109/1596] DocBook/drm: Remove extraneous commas Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 790e634e5635..d2aee84f18af 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -562,9 +562,9 @@ void intel_crt_init(struct drm_device *dev) In the example above (again, taken from the i915 driver), a CRT connector and encoder combination is created. A device - specific i2c bus is also created, for fetching EDID data and + specific i2c bus is also created for fetching EDID data and performing monitor detection. Once the process is complete, - the new connector is registered with sysfs, to make its + the new connector is registered with sysfs to make its properties available to applications. From 4dc0152d5780f04573046b06a3fb7c7ad9b81afa Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 20:29:32 +0000 Subject: [PATCH 0110/1596] DocBook/drm: Insert `the' for readability, and change `set' to `setting' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index d2aee84f18af..09e02f7c668c 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -573,8 +573,8 @@ void intel_crt_init(struct drm_device *dev) Since many PC-class graphics devices have similar display output designs, the DRM provides a set of helper functions to make output management easier. The core helper routines handle - encoder re-routing and disabling of unused functions following - mode set. Using the helpers is optional, but recommended for + encoder re-routing and the disabling of unused functions following + mode setting. Using the helpers is optional, but recommended for devices with PC-style architectures (i.e. a set of display planes for feeding pixels to encoders which are in turn routed to connectors). Devices with more complex requirements needing From 65ffef508f23d5e67940cadc8eca2ae34738018a Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 20:55:58 +0000 Subject: [PATCH 0111/1596] DocBook/drm: Use an itemizedlist for what an encoder needs to provide Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 09e02f7c668c..da011f2af9cb 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -586,17 +586,25 @@ void intel_crt_init(struct drm_device *dev) - For each encoder, CRTC, and connector, several functions must - be provided, depending on the object type. Encoder objects - need to provide a DPMS (basically on/off) function, mode fixup - (for converting requested modes into native hardware timings), - and prepare, set and commit functions for use by the core DRM - helper functions. Connector helpers need to provide mode fetch and - validity functions as well as an encoder matching function for - returning an ideal encoder for a given connector. The core - connector functions include a DPMS callback, (deprecated) - save/restore routines, detection, mode probing, property handling, - and cleanup functions. + Each encoder object needs to provide: + + + A DPMS (basically on/off) function. + + + A mode-fixup function (for converting requested modes into + native hardware timings). + + + Functions (prepare, set, and commit) for use by the core DRM + helper functions. + + + Connector helpers need to provide functions (mode-fetch, validity, + and encoder-matching) for returning an ideal encoder for a given + connector. The core connector functions include a DPMS callback, + save/restore routines (deprecated), detection, mode probing, + property handling, and cleanup functions. From 51b9500de28a1e5e7a2090de5d345d6d98581617 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 21:11:30 +0000 Subject: [PATCH 0112/1596] DocBook/drm: Use a for vblank ioctls Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 39 ++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index da011f2af9cb..457d56a1a966 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -619,22 +619,33 @@ void intel_crt_init(struct drm_device *dev) VBlank event handling The DRM core exposes two vertical blank related ioctls: - DRM_IOCTL_WAIT_VBLANK and DRM_IOCTL_MODESET_CTL. + + + DRM_IOCTL_WAIT_VBLANK + + + This takes a struct drm_wait_vblank structure as its argument, + and it is used to block or request a signal when a specified + vblank event occurs. + + + + + DRM_IOCTL_MODESET_CTL + + + This should be called by application level drivers before and + after mode setting, since on many devices the vertical blank + counter is reset at that time. Internally, the DRM snapshots + the last vblank count when the ioctl is called with the + _DRM_PRE_MODESET command so that the counter won't go backwards + (which is dealt with when _DRM_POST_MODESET is used). + + + + - - DRM_IOCTL_WAIT_VBLANK takes a struct drm_wait_vblank structure - as its argument, and is used to block or request a signal when a - specified vblank event occurs. - - - DRM_IOCTL_MODESET_CTL should be called by application level - drivers before and after mode setting, since on many devices, the - vertical blank counter is reset at that time. Internally, - the DRM snapshots the last vblank count when the ioctl is called - with the _DRM_PRE_MODESET command so that the counter won't go - backwards (which is dealt with when _DRM_POST_MODESET is used). - To support the functions above, the DRM core provides several helper functions for tracking vertical blank counters, and From f877bd4ad5508e2f0653c31d05ffe0ad4e2bfe11 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Thu, 25 Aug 2011 21:16:15 +0000 Subject: [PATCH 0113/1596] DocBook/drm: Insert a comma Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 457d56a1a966..0387970234b3 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -638,7 +638,7 @@ void intel_crt_init(struct drm_device *dev) after mode setting, since on many devices the vertical blank counter is reset at that time. Internally, the DRM snapshots the last vblank count when the ioctl is called with the - _DRM_PRE_MODESET command so that the counter won't go backwards + _DRM_PRE_MODESET command, so that the counter won't go backwards (which is dealt with when _DRM_POST_MODESET is used). From 0c2d91a80a156208d2f9f3dfb01871ebcf4a9338 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 15:59:56 +0000 Subject: [PATCH 0114/1596] DocBook/drm: Use an for fundamental GEM operations Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 0387970234b3..c358367f9f85 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -709,9 +709,13 @@ void intel_crt_init(struct drm_device *dev) read & write, mapping, and domain ownership transfers. - On a fundamental level, GEM involves several operations: memory - allocation and freeing, command execution, and aperture management - at command execution time. Buffer object allocation is relatively + On a fundamental level, GEM involves several operations: + + Memory allocation and freeing + Command execution + Aperture management at command execution time + + Buffer object allocation is relatively straightforward and largely provided by Linux's shmem layer, which provides memory to back each object. When mapped into the GTT or used in a command buffer, the backing pages for an object are From 2d43f5d667273ba4975cb79782a46aa374dd8607 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 16:00:55 +0000 Subject: [PATCH 0115/1596] DocBook/drm: Improve flow of GPU/CPU coherence sentence Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index c358367f9f85..ba20f9fbb62b 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -720,8 +720,9 @@ void intel_crt_init(struct drm_device *dev) provides memory to back each object. When mapped into the GTT or used in a command buffer, the backing pages for an object are flushed to memory and marked write combined so as to be coherent - with the GPU. Likewise, when the GPU finishes rendering to an object, - if the CPU accesses it, it must be made coherent with the CPU's view + with the GPU. Likewise, if the CPU accesses an object after the GPU + has finished rendering to the object, then the object must be made + coherent with the CPU's view of memory, usually involving GPU cache flushing of various kinds. This core CPU<->GPU coherency management is provided by the GEM set domain function, which evaluates an object's current domain and From b8c6e0fe46fcd60f58089365dd96dcf04f95263b Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 17:34:00 +0000 Subject: [PATCH 0116/1596] DocBook/drm: Refer to the domain-setting function as a device-specific ioctl Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index ba20f9fbb62b..9ae328aa1dd3 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -724,11 +724,11 @@ void intel_crt_init(struct drm_device *dev) has finished rendering to the object, then the object must be made coherent with the CPU's view of memory, usually involving GPU cache flushing of various kinds. - This core CPU<->GPU coherency management is provided by the GEM - set domain function, which evaluates an object's current domain and + This core CPU<->GPU coherency management is provided by a + device-specific ioctl, which evaluates an object's current domain and performs any necessary flushing or synchronization to put the object into the desired coherency domain (note that the object may be busy, - i.e. an active render target; in that case, the set domain function + i.e. an active render target; in that case, setting the domain blocks the client and waits for rendering to complete before performing any necessary flushing operations). From e355b2014da06458385902c47edf193a997895fc Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 17:38:48 +0000 Subject: [PATCH 0117/1596] DocBook/drm: Better flow with `, and then' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 9ae328aa1dd3..0b6c59d6aa5f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -735,8 +735,8 @@ void intel_crt_init(struct drm_device *dev) Perhaps the most important GEM function is providing a command execution interface to clients. Client programs construct command - buffers containing references to previously allocated memory objects - and submit them to GEM. At that point, GEM takes care to bind + buffers containing references to previously allocated memory objects, + and then submit them to GEM. At that point, GEM takes care to bind all the objects into the GTT, execute the buffer, and provide necessary synchronization between clients accessing the same buffers. This often involves evicting some objects from the GTT and re-binding From 964d32dcbefcfda015bc33dc76414b05c6f512de Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 17:41:31 +0000 Subject: [PATCH 0118/1596] DocBook/drm: Use `; otherwise,' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 0b6c59d6aa5f..606a989d8895 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -743,7 +743,7 @@ void intel_crt_init(struct drm_device *dev) others (a fairly expensive operation), and providing relocation support which hides fixed GTT offsets from clients. Clients must take care not to submit command buffers that reference more objects - than can fit in the GTT or GEM will reject them and no rendering + than can fit in the GTT; otherwise, GEM will reject them and no rendering will occur. Similarly, if several objects in the buffer require fence registers to be allocated for correct rendering (e.g. 2D blits on pre-965 chips), care must be taken not to require more fence From 5a462d58c84a2f5ed161daced2c7df34357c6d3d Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 17:58:46 +0000 Subject: [PATCH 0119/1596] DocBook/drm: Clean up the paragraph on framebuffer objects Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 606a989d8895..a39e76bae03d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -795,14 +795,12 @@ void intel_crt_init(struct drm_device *dev) Framebuffer management - In order to set a mode on a given CRTC, encoder and connector - configuration, clients need to provide a framebuffer object which - provides a source of pixels for the CRTC to deliver to the encoder(s) - and ultimately the connector(s) in the configuration. A framebuffer - is fundamentally a driver specific memory object, made into an opaque - handle by the DRM addfb function. Once an fb has been created this - way it can be passed to the KMS mode setting routines for use in - a configuration. + Clients need to provide a framebuffer object which provides a source + of pixels for a CRTC to deliver to the encoder(s) and ultimately the + connector(s). A framebuffer is fundamentally a driver specific memory + object, made into an opaque handle by the DRM's addfb() function. + Once a framebuffer has been created this way, it may be passed to the + KMS mode setting routines for use in a completed configuration. From a5294e01f2777649834d218583e7a32b2dacb699 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 18:05:52 +0000 Subject: [PATCH 0120/1596] DocBook/drm: `(device|driver) specific' -> `(device|driver)-specific' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index a39e76bae03d..65e14f96f943 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -238,7 +238,7 @@ In this specific case, the driver requires AGP and supports - IRQs. DMA, as discussed later, is handled by device specific ioctls + IRQs. DMA, as discussed later, is handled by device-specific ioctls in this case. It also supports the kernel mode setting APIs, though unlike in the actual i915 driver source, this example unconditionally exports KMS capability. @@ -277,7 +277,7 @@ to perform output discovery & configuration at load time. Likewise, if user-level drivers unaware of memory management are in use, memory management and command buffer setup may need to - be omitted. These requirements are driver specific, and care + be omitted. These requirements are driver-specific, and care needs to be taken to keep both old and new applications and libraries working. The i915 driver supports the "modeset" module parameter to control whether advanced features are @@ -288,7 +288,7 @@ Driver private & performance counters The driver private hangs off the main drm_device structure and - can be used for tracking various device specific bits of + can be used for tracking various device-specific bits of information, like register offsets, command buffer status, register state for suspend/resume, etc. At load time, a driver may simply allocate one and set drm_device.dev_priv @@ -313,7 +313,7 @@ Configuring the device - Obviously, device configuration is device specific. + Obviously, device configuration is device-specific. However, there are several common operations: finding a device's PCI resources, mapping them, and potentially setting up an IRQ handler. @@ -340,8 +340,8 @@ Once you have a register map, you may use the DRM_READn() and DRM_WRITEn() macros to access the registers on your device, or - use driver specific versions to offset into your MMIO space - relative to a driver specific base pointer (see I915_READ for + use driver-specific versions to offset into your MMIO space + relative to a driver-specific base pointer (see I915_READ for an example). @@ -399,7 +399,7 @@ and devices with dedicated video RAM (VRAM), i.e. most discrete graphics devices. If your device has dedicated RAM, supporting TTM is desirable. TTM also integrates tightly with your - driver specific buffer execution function. See the radeon + driver-specific buffer execution function. See the radeon driver for examples. @@ -427,7 +427,7 @@ created by the memory manager at runtime. Your global TTM should have a type of TTM_GLOBAL_TTM_MEM. The size field for the global object should be sizeof(struct ttm_mem_global), and the init and - release hooks should point at your driver specific init and + release hooks should point at your driver-specific init and release routines, which probably eventually call ttm_mem_global_init and ttm_mem_global_release, respectively. @@ -438,7 +438,7 @@ provide a pool for buffer object allocation by clients and the kernel itself. The type of this object should be TTM_GLOBAL_TTM_BO, and its size should be sizeof(struct ttm_bo_global). Again, - driver specific init and release functions may be provided, + driver-specific init and release functions may be provided, likely eventually calling ttm_bo_global_init() and ttm_bo_global_release(), respectively. Also, like the previous object, ttm_global_item_ref() is used to create an initial reference @@ -462,7 +462,7 @@ be initialized separately into its own DRM MM object. - Initialization is driver specific. In the case of Intel + Initialization is driver-specific. In the case of Intel integrated graphics chips like 965GM, GEM initialization can be done by calling the internal GEM init function, i915_gem_do_init(). Since the 965GM is a UMA device @@ -561,8 +561,8 @@ void intel_crt_init(struct drm_device *dev) In the example above (again, taken from the i915 driver), a - CRT connector and encoder combination is created. A device - specific i2c bus is also created for fetching EDID data and + CRT connector and encoder combination is created. A device-specific + i2c bus is also created for fetching EDID data and performing monitor detection. Once the process is complete, the new connector is registered with sysfs to make its properties available to applications. @@ -704,8 +704,8 @@ void intel_crt_init(struct drm_device *dev) GEM-enabled drivers must provide gem_init_object() and gem_free_object() callbacks to support the core memory - allocation routines. They should also provide several driver - specific ioctls to support command execution, pinning, buffer + allocation routines. They should also provide several driver-specific + ioctls to support command execution, pinning, buffer read & write, mapping, and domain ownership transfers. @@ -797,7 +797,7 @@ void intel_crt_init(struct drm_device *dev) Clients need to provide a framebuffer object which provides a source of pixels for a CRTC to deliver to the encoder(s) and ultimately the - connector(s). A framebuffer is fundamentally a driver specific memory + connector(s). A framebuffer is fundamentally a driver-specific memory object, made into an opaque handle by the DRM's addfb() function. Once a framebuffer has been created this way, it may be passed to the KMS mode setting routines for use in a completed configuration. @@ -807,7 +807,7 @@ void intel_crt_init(struct drm_device *dev) Command submission & fencing - This should cover a few device specific command submission + This should cover a few device-specific command submission implementations. @@ -840,7 +840,7 @@ void intel_crt_init(struct drm_device *dev) The DRM core exports several interfaces to applications, generally intended to be used through corresponding libdrm - wrapper functions. In addition, drivers export device specific + wrapper functions. In addition, drivers export device-specific interfaces for use by userspace drivers & device aware applications through ioctls and sysfs files. From 7f0925aca586b4a0cce81b06af7383d6aec59cc1 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 18:07:13 +0000 Subject: [PATCH 0121/1596] DocBook/drm: `device aware' -> `device-aware' Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 65e14f96f943..9da9b2831370 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -841,7 +841,7 @@ void intel_crt_init(struct drm_device *dev) The DRM core exports several interfaces to applications, generally intended to be used through corresponding libdrm wrapper functions. In addition, drivers export device-specific - interfaces for use by userspace drivers & device aware + interfaces for use by userspace drivers & device-aware applications through ioctls and sysfs files. From bcd3cfc1213894ff955771508d46fa18d66e9328 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Mon, 29 Aug 2011 19:29:16 +0000 Subject: [PATCH 0122/1596] DocBook/drm: Clean up a todo-note Signed-off-by: Michael Witten --- Documentation/DocBook/drm.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 9da9b2831370..196b8b9dba11 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -850,8 +850,8 @@ void intel_crt_init(struct drm_device *dev) management, memory management, and output management. - Cover generic ioctls and sysfs layout here. Only need high - level info, since man pages should cover the rest. + Cover generic ioctls and sysfs layout here. We only need high-level + info, since man pages should cover the rest. From 953742c8fe8ac45be453fee959d7be40cd89f920 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Tue, 16 Aug 2011 01:20:20 -0400 Subject: [PATCH 0123/1596] kconfig: fix __enabled_ macros definition for invisible and un-selected symbols __enabled_ are only generated on visible or selected entries, do not reflect the purpose of its introduction. Fix this by always generating these entries for named symbol. Reported-by: Rabin Vincent Signed-off-by: Arnaud Lacombe --- scripts/kconfig/confdata.c | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 59b667cae5f3..5a58965d8800 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -503,17 +503,6 @@ header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) fprintf(fp, "#define %s%s%s 1\n", CONFIG_, sym->name, suffix); } - /* - * Generate the __enabled_CONFIG_* and - * __enabled_CONFIG_*_MODULE macros for use by the - * IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is - * generated even for booleans so that the IS_ENABLED() macro - * works. - */ - fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n", - sym->name, (*value == 'y')); - fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n", - sym->name, (*value == 'm')); break; } case S_HEX: { @@ -564,6 +553,35 @@ static struct conf_printer header_printer_cb = .print_comment = header_print_comment, }; +/* + * Generate the __enabled_CONFIG_* and __enabled_CONFIG_*_MODULE macros for + * use by the IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is + * generated even for booleans so that the IS_ENABLED() macro works. + */ +static void +header_print__enabled_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: { + fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n", + sym->name, (*value == 'y')); + fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n", + sym->name, (*value == 'm')); + break; + } + default: + break; + } +} + +static struct conf_printer header__enabled_printer_cb = +{ + .print_symbol = header_print__enabled_symbol, + .print_comment = header_print_comment, +}; + /* * Tristate printer * @@ -945,11 +963,16 @@ int conf_write_autoconf(void) conf_write_heading(out_h, &header_printer_cb, NULL); for_all_symbols(i, sym) { + if (!sym->name) + continue; + sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE) || !sym->name) + + conf_write_symbol(out_h, sym, &header__enabled_printer_cb, NULL); + + if (!(sym->flags & SYMBOL_WRITE)) continue; - /* write symbol to auto.conf, tristate and header files */ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); From 564899f9f0a2df85fa367c8749a1fef323cb3215 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Sun, 21 Aug 2011 22:04:09 -0300 Subject: [PATCH 0124/1596] kconfig: handle SIGINT in menuconfig I recently got bitten in the ass when pressing Ctrl-C and lost all my current configuration changes. This patch captures SIGINT and allows the user to save any changes. Some code refactoring was made in order to handle the exit behavior. Signed-off-by: Davidlohr Bueso Signed-off-by: Arnaud Lacombe --- scripts/kconfig/mconf.c | 86 +++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 820d2b6800fb..19e200d91120 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -272,6 +273,7 @@ static struct menu *current_menu; static int child_count; static int single_menu_mode; static int show_all_options; +static int saved_x, saved_y; static void conf(struct menu *menu); static void conf_choice(struct menu *menu); @@ -792,9 +794,54 @@ static void conf_save(void) } } +static int handle_exit(void) +{ + int res; + + dialog_clear(); + if (conf_get_changed()) + res = dialog_yesno(NULL, + _("Do you wish to save your new configuration ?\n" + " to continue."), + 6, 60); + else + res = -1; + + end_dialog(saved_x, saved_y); + + switch (res) { + case 0: + if (conf_write(filename)) { + fprintf(stderr, _("\n\n" + "Error while writing of the configuration.\n" + "Your configuration changes were NOT saved." + "\n\n")); + return 1; + } + /* fall through */ + case -1: + printf(_("\n\n" + "*** End of the configuration.\n" + "*** Execute 'make' to start the build or try 'make help'." + "\n\n")); + res = 0; + break; + default: + fprintf(stderr, _("\n\n" + "Your configuration changes were NOT saved." + "\n\n")); + } + + return res; +} + +static void sig_handler(int signo) +{ + exit(handle_exit()); +} + int main(int ac, char **av) { - int saved_x, saved_y; char *mode; int res; @@ -802,6 +849,8 @@ int main(int ac, char **av) bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); + signal(SIGINT, sig_handler); + conf_parse(av[1]); conf_read(NULL); @@ -823,40 +872,9 @@ int main(int ac, char **av) set_config_filename(conf_get_configname()); do { conf(&rootmenu); - dialog_clear(); - if (conf_get_changed()) - res = dialog_yesno(NULL, - _("Do you wish to save your " - "new configuration?\n" - " to continue."), - 6, 60); - else - res = -1; + res = handle_exit(); } while (res == KEY_ESC); - end_dialog(saved_x, saved_y); - - switch (res) { - case 0: - if (conf_write(filename)) { - fprintf(stderr, _("\n\n" - "Error while writing of the configuration.\n" - "Your configuration changes were NOT saved." - "\n\n")); - return 1; - } - /* fall through */ - case -1: - printf(_("\n\n" - "*** End of the configuration.\n" - "*** Execute 'make' to start the build or try 'make help'." - "\n\n")); - break; - default: - fprintf(stderr, _("\n\n" - "Your configuration changes were NOT saved." - "\n\n")); - } - return 0; + return res; } From 702a945028fd7cbf7a5e55546b3c47a5c984a1ba Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Sat, 20 Aug 2011 02:28:53 -0300 Subject: [PATCH 0125/1596] kconfig: fix set but not used variables Some variables were being set but never used, which was triggering warnings in GCC >= 4.6. Signed-off-by: Lucas De Marchi Signed-off-by: Arnaud Lacombe --- scripts/kconfig/lxdialog/textbox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index c704712d0227..154c2dd245b7 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c @@ -320,7 +320,6 @@ static void print_page(WINDOW * win, int height, int width) */ static void print_line(WINDOW * win, int row, int width) { - int y, x; char *line; line = get_line(); @@ -329,10 +328,10 @@ static void print_line(WINDOW * win, int row, int width) waddch(win, ' '); waddnstr(win, line, MIN(strlen(line), width - 2)); - getyx(win, y, x); /* Clear 'residue' of previous line */ #if OLD_NCURSES { + int x = getcurx(win); int i; for (i = 0; i < width - x; i++) waddch(win, ' '); From 09d481270d445d98342d8ab872f05491b6d23f8b Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 16 Aug 2011 10:46:05 +0200 Subject: [PATCH 0126/1596] scripts: add extract-vmlinux This script can be used to extract vmlinux from a compressed kernel image (bzImage, etc..). It's inspired from (a subset of) extract-ikconfig. It's something a lot of people have been looking for (mainly people with xen < 4 that doesn't support bzImages at all). Signed-off-by: Corentin Chary Signed-off-by: Michal Marek --- scripts/extract-vmlinux | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100755 scripts/extract-vmlinux diff --git a/scripts/extract-vmlinux b/scripts/extract-vmlinux new file mode 100755 index 000000000000..5061abcc2540 --- /dev/null +++ b/scripts/extract-vmlinux @@ -0,0 +1,62 @@ +#!/bin/sh +# ---------------------------------------------------------------------- +# extract-vmlinux - Extract uncompressed vmlinux from a kernel image +# +# Inspired from extract-ikconfig +# (c) 2009,2010 Dick Streefland +# +# (c) 2011 Corentin Chary +# +# Licensed under the GNU General Public License, version 2 (GPLv2). +# ---------------------------------------------------------------------- + +check_vmlinux() +{ + # Use readelf to check if it's a valid ELF + # TODO: find a better to way to check that it's really vmlinux + # and not just an elf + readelf -h $1 > /dev/null 2>&1 || return 1 + + cat $1 + exit 0 +} + +try_decompress() +{ + # The obscure use of the "tr" filter is to work around older versions of + # "grep" that report the byte offset of the line instead of the pattern. + + # Try to find the header ($1) and decompress from here + for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"` + do + pos=${pos%%:*} + tail -c+$pos "$img" | $3 > $tmp 2> /dev/null + check_vmlinux $tmp + done +} + +# Check invocation: +me=${0##*/} +img=$1 +if [ $# -ne 1 -o ! -s "$img" ] +then + echo "Usage: $me " >&2 + exit 2 +fi + +# Prepare temp files: +tmp=$(mktemp /tmp/vmlinux-XXX) +trap "rm -f $tmp" 0 + +# Initial attempt for uncompressed images or objects: +check_vmlinux $img + +# That didn't work, so retry after decompression. +try_decompress '\037\213\010' xy gunzip +try_decompress '\3757zXZ\000' abcde unxz +try_decompress 'BZh' xy bunzip2 +try_decompress '\135\0\0\0' xxx unlzma +try_decompress '\211\114\132' xy 'lzop -d' + +# Bail out: +echo "$me: Cannot find vmlinux." >&2 From 9c65426ad2cce12a2d72cdb42aa08f7ce946065d Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Tue, 30 Aug 2011 11:47:58 +1000 Subject: [PATCH 0127/1596] tags, powerpc: Update tags.sh to support _GLOBAL symbols On PowerPC we use _GLOBAL throughout the assembly to define symbols, but currently these symbols are missing from the tags generated with ARCH=powerpc make tags. This patch modifies the tags.sh script to recognise _GLOBAL(.*) so that these symbols will be in the tags. This is almost (but not quite) PowerPC specific and this change should not affect anyone else: $ git grep -E '^_GLOBAL\(([^)]*)\).*' |sed 's/^\([^/]*\/[^/]*\)\/.*$/\1/'|uniq -c 627 arch/powerpc 2 arch/um Signed-off-by: Ian Munsie Signed-off-by: Michal Marek --- scripts/tags.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tags.sh b/scripts/tags.sh index 75c5d24f1993..38f6617a2cb1 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -129,7 +129,7 @@ exuberant() -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ --extra=+f --c-kinds=+px \ - --regex-asm='/^ENTRY\(([^)]*)\).*/\1/' \ + --regex-asm='/^(ENTRY|_GLOBAL)\(([^)]*)\).*/\2/' \ --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \ --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/' @@ -151,7 +151,7 @@ exuberant() emacs() { all_sources | xargs $1 -a \ - --regex='/^ENTRY(\([^)]*\)).*/\1/' \ + --regex='/^(ENTRY|_GLOBAL)(\([^)]*\)).*/\2/' \ --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/' \ --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/' \ --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/' From 58238c81443a83922e07b409e54ec93ce909b6ac Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sun, 31 Jul 2011 14:45:40 -0400 Subject: [PATCH 0128/1596] kbuild: prevent make from deleting _shipped files commit 7373f4f (kbuild: add implicit rules for parser generation) created a implicit rule chain (%.c: %.c_shipped: %.y). Make considers the _shipped files to be intermediate files which causes them to be deleted if they didn't exist before make was run. Mark the _shipped files PRECIOUS to prevent make from deleting them. Signed-off-by: Peter Foley Acked-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/Makefile.lib | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index aeea84a24836..5d986d9adf1b 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -167,6 +167,7 @@ ifdef REGENERATE_PARSERS quiet_cmd_gperf = GPERF $@ cmd_gperf = gperf -t --output-file $@ -a -C -E -g -k 1,3,$$ -p -t $< +.PRECIOUS: $(src)/%.hash.c_shipped $(src)/%.hash.c_shipped: $(src)/%.gperf $(call cmd,gperf) @@ -177,6 +178,7 @@ LEX_PREFIX = $(if $(LEX_PREFIX_${baseprereq}),$(LEX_PREFIX_${baseprereq}),yy) quiet_cmd_flex = LEX $@ cmd_flex = flex -o$@ -L -P $(LEX_PREFIX) $< +.PRECIOUS: $(src)/%.lex.c_shipped $(src)/%.lex.c_shipped: $(src)/%.l $(call cmd,flex) @@ -187,12 +189,14 @@ YACC_PREFIX = $(if $(YACC_PREFIX_${baseprereq}),$(YACC_PREFIX_${baseprereq}),yy) quiet_cmd_bison = YACC $@ cmd_bison = bison -o$@ -t -l -p $(YACC_PREFIX) $< +.PRECIOUS: $(src)/%.tab.c_shipped $(src)/%.tab.c_shipped: $(src)/%.y $(call cmd,bison) quiet_cmd_bison_h = YACC $@ cmd_bison_h = bison -o/dev/null --defines=$@ -t -l -p $(YACC_PREFIX) $< +.PRECIOUS: $(src)/%.tab.h_shipped $(src)/%.tab.h_shipped: $(src)/%.y $(call cmd,bison_h) From 49c57d254e691a45ade207c754ba09ca7129ed93 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Mon, 15 Aug 2011 01:07:13 -0400 Subject: [PATCH 0129/1596] scripts/Makefile.build: do not reference EXTRA_CFLAGS as CFLAGS replacement Usage of these flags has been deprecated for nearly 4 years by: commit f77bf01425b11947eeb3b5b54685212c302741b8 Author: Sam Ravnborg Date: Mon Oct 15 22:25:06 2007 +0200 kbuild: introduce ccflags-y, asflags-y and ldflags-y Moreover, these flags (at least EXTRA_CFLAGS) have been documented for command line use. By default, gmake(1) do not override command line setting, so this is likely to result in build failure or unexpected behavior. Do not advertise for its usage. Cc: Sam Ravnborg Cc: linux-kbuild@vger.kernel.org Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/Makefile.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index a0fd5029cfe7..d2b366c16b64 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -46,7 +46,7 @@ include $(kbuild-file) # If the save-* variables changed error out ifeq ($(KBUILD_NOPEDANTIC),) ifneq ("$(save-cflags)","$(CFLAGS)") - $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use EXTRA_CFLAGS) + $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y) endif endif From c68e58783f20d3eb32b99e1962b26462f2e3195a Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Mon, 15 Aug 2011 01:07:14 -0400 Subject: [PATCH 0130/1596] script/checkpatch.pl: warn about deprecated use of EXTRA_{A,C,CPP,LD}FLAGS Usage of these flags has been deprecated for nearly 4 years by: commit f77bf01425b11947eeb3b5b54685212c302741b8 Author: Sam Ravnborg Date: Mon Oct 15 22:25:06 2007 +0200 kbuild: introduce ccflags-y, asflags-y and ldflags-y Moreover, these flags (at least EXTRA_CFLAGS) have been documented for command line use. By default, gmake(1) do not override command line setting, so this is likely to result in build failure or unexpected behavior. Warn about their introduction in Makefile or Kbuild files. Cc: Sam Ravnborg Cc: Andy Whitcroft Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/checkpatch.pl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 9d761c95eca2..955183ada37a 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1661,6 +1661,20 @@ sub process { #print "is_end<$is_end> length<$length>\n"; } + if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) && + ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) { + my $flag = $1; + my $replacement = { + 'EXTRA_AFLAGS' => 'asflags-y', + 'EXTRA_CFLAGS' => 'ccflags-y', + 'EXTRA_CPPFLAGS' => 'cppflags-y', + 'EXTRA_LDFLAGS' => 'ldflags-y', + }; + + WARN("DEPRECATED_VARIABLE", + "Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag}); + } + # check we are in a valid source file if not then ignore this hunk next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); From ce395088832bfd56bd28824b31a6a3685f3fd339 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 17 Jun 2011 02:51:47 +0000 Subject: [PATCH 0131/1596] cpc925_edac: Support single-processor configurations If second CPU is not enabled, CPC925 EDAC driver will spill out warnings about errors on second Processor Interface. Support masking that out, by detecting at runtime which CPUs are present in device tree. Signed-off-by: Dmitry Eremin-Solenikov Cc: Harry Ciao Cc: Doug Thompson Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Benjamin Herrenschmidt --- drivers/edac/cpc925_edac.c | 67 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index a687a0d16962..a774c0ddaf5b 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -90,6 +90,7 @@ enum apimask_bits { ECC_MASK_ENABLE = (APIMASK_ECC_UE_H | APIMASK_ECC_CE_H | APIMASK_ECC_UE_L | APIMASK_ECC_CE_L), }; +#define APIMASK_ADI(n) CPC925_BIT(((n)+1)) /************************************************************ * Processor Interface Exception Register (APIEXCP) @@ -581,16 +582,73 @@ static void cpc925_mc_check(struct mem_ctl_info *mci) } /******************** CPU err device********************************/ +static u32 cpc925_cpu_mask_disabled(void) +{ + struct device_node *cpus; + struct device_node *cpunode = NULL; + static u32 mask = 0; + + /* use cached value if available */ + if (mask != 0) + return mask; + + mask = APIMASK_ADI0 | APIMASK_ADI1; + + cpus = of_find_node_by_path("/cpus"); + if (cpus == NULL) { + cpc925_printk(KERN_DEBUG, "No /cpus node !\n"); + return 0; + } + + while ((cpunode = of_get_next_child(cpus, cpunode)) != NULL) { + const u32 *reg = of_get_property(cpunode, "reg", NULL); + + if (strcmp(cpunode->type, "cpu")) { + cpc925_printk(KERN_ERR, "Not a cpu node in /cpus: %s\n", cpunode->name); + continue; + } + + if (reg == NULL || *reg > 2) { + cpc925_printk(KERN_ERR, "Bad reg value at %s\n", cpunode->full_name); + continue; + } + + mask &= ~APIMASK_ADI(*reg); + } + + if (mask != (APIMASK_ADI0 | APIMASK_ADI1)) { + /* We assume that each CPU sits on it's own PI and that + * for present CPUs the reg property equals to the PI + * interface id */ + cpc925_printk(KERN_WARNING, + "Assuming PI id is equal to CPU MPIC id!\n"); + } + + of_node_put(cpunode); + of_node_put(cpus); + + return mask; +} + /* Enable CPU Errors detection */ static void cpc925_cpu_init(struct cpc925_dev_info *dev_info) { u32 apimask; + u32 cpumask; apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); - if ((apimask & CPU_MASK_ENABLE) == 0) { - apimask |= CPU_MASK_ENABLE; - __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET); + + cpumask = cpc925_cpu_mask_disabled(); + if (apimask & cpumask) { + cpc925_printk(KERN_WARNING, "CPU(s) not present, " + "but enabled in APIMASK, disabling\n"); + apimask &= ~cpumask; } + + if ((apimask & CPU_MASK_ENABLE) == 0) + apimask |= CPU_MASK_ENABLE; + + __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET); } /* Disable CPU Errors detection */ @@ -622,6 +680,9 @@ static void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev) if ((apiexcp & CPU_EXCP_DETECTED) == 0) return; + if ((apiexcp & ~cpc925_cpu_mask_disabled()) == 0) + return; + apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); cpc925_printk(KERN_INFO, "Processor Interface Fault\n" "Processor Interface register dump:\n"); From 6a5c7be5e484bda5b2639fedf7dbe3f25c15c962 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Fri, 24 Jun 2011 09:05:22 +0000 Subject: [PATCH 0132/1596] powerpc: Override dma_get_required_mask by platform hook and ops The hook dma_get_required_mask is supposed to return the mask required by the platform to operate efficently. The generic version of dma_get_required_mask in driver/base/platform.c returns a mask based only on max_pfn. However, this is likely too big for iommu systems and could be too small for platforms that require a dma offset or have a secondary window at a high offset. Override the default, provide a hook in ppc_md used by pseries lpar and cell, and provide the default answer based on memblock_end_of_DRAM(), with hooks for get_dma_offset, and provide an implementation for iommu that looks at the defined table size. Coverting from the end address to the required bit mask is based on the generic implementation. The need for this was discovered when the qla2xxx driver switched to 64 bit dma then reverted to 32 bit when dma_get_required_mask said 32 bits was sufficient. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org Cc: benh@kernel.crashing.org Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/dma-mapping.h | 3 ++ arch/powerpc/include/asm/machdep.h | 3 +- arch/powerpc/kernel/dma-iommu.c | 13 +++++++++ arch/powerpc/kernel/dma.c | 39 ++++++++++++++++++++++++++ arch/powerpc/platforms/cell/iommu.c | 12 ++++++++ arch/powerpc/platforms/pseries/iommu.c | 27 ++++++++++++++++++ 6 files changed, 96 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index dd70fac57ec8..8135e66a4bb9 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -20,6 +20,8 @@ #define DMA_ERROR_CODE (~(dma_addr_t)0x0) +#define ARCH_HAS_DMA_GET_REQUIRED_MASK + /* Some dma direct funcs must be visible for use in other dma_ops */ extern void *dma_direct_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag); @@ -69,6 +71,7 @@ static inline unsigned long device_to_mask(struct device *dev) */ #ifdef CONFIG_PPC64 extern struct dma_map_ops dma_iommu_ops; +extern u64 dma_iommu_get_required_mask(struct device *dev); #endif extern struct dma_map_ops dma_direct_ops; diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 47cacddb14cf..58fc21623014 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -85,8 +85,9 @@ struct machdep_calls { void (*pci_dma_dev_setup)(struct pci_dev *dev); void (*pci_dma_bus_setup)(struct pci_bus *bus); - /* Platform set_dma_mask override */ + /* Platform set_dma_mask and dma_get_required_mask overrides */ int (*dma_set_mask)(struct device *dev, u64 dma_mask); + u64 (*dma_get_required_mask)(struct device *dev); int (*probe)(void); void (*setup_arch)(void); /* Optional, may be NULL */ diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index e7554154a6de..1f2a711a261e 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -90,6 +90,19 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask) return 1; } +u64 dma_iommu_get_required_mask(struct device *dev) +{ + struct iommu_table *tbl = get_iommu_table_base(dev); + u64 mask; + if (!tbl) + return 0; + + mask = 1ULL < (fls_long(tbl->it_offset + tbl->it_size) - 1); + mask += mask - 1; + + return mask; +} + struct dma_map_ops dma_iommu_ops = { .alloc_coherent = dma_iommu_alloc_coherent, .free_coherent = dma_iommu_free_coherent, diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 4f0959fbfbee..503093efa202 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -170,6 +170,45 @@ int dma_set_mask(struct device *dev, u64 dma_mask) } EXPORT_SYMBOL(dma_set_mask); +u64 dma_get_required_mask(struct device *dev) +{ + struct dma_map_ops *dma_ops = get_dma_ops(dev); + u64 mask, end = 0; + + if (ppc_md.dma_get_required_mask) + return ppc_md.dma_get_required_mask(dev); + + if (unlikely(dma_ops == NULL)) + return 0; + +#ifdef CONFIG_PPC64 + else if (dma_ops == &dma_iommu_ops) + return dma_iommu_get_required_mask(dev); +#endif +#ifdef CONFIG_SWIOTLB + else if (dma_ops == &swiotlb_dma_ops) { + u64 max_direct_dma_addr = dev->archdata.max_direct_dma_addr; + + end = memblock_end_of_DRAM(); + if (max_direct_dma_addr && end > max_direct_dma_addr) + end = max_direct_dma_addr; + end += get_dma_offset(dev); + } +#endif + else if (dma_ops == &dma_direct_ops) + end = memblock_end_of_DRAM() + get_dma_offset(dev); + else { + WARN_ONCE(1, "%s: unknown ops %p\n", __func__, dma_ops); + end = memblock_end_of_DRAM(); + } + + mask = 1ULL << (fls64(end) - 1); + mask += mask - 1; + + return mask; +} +EXPORT_SYMBOL_GPL(dma_get_required_mask); + static int __init dma_init(void) { dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 26a067122a54..5ef55f3b0987 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -1159,6 +1159,17 @@ static int __init setup_iommu_fixed(char *str) } __setup("iommu_fixed=", setup_iommu_fixed); +static u64 cell_dma_get_required_mask(struct device *dev) +{ + if (!dev->dma_mask) + return 0; + + if (iommu_fixed_disabled && get_dma_ops(dev) == &dma_iommu_ops) + return dma_iommu_get_required_mask(dev); + + return DMA_BIT_MASK(64); +} + static int __init cell_iommu_init(void) { struct device_node *np; @@ -1175,6 +1186,7 @@ static int __init cell_iommu_init(void) /* Setup various ppc_md. callbacks */ ppc_md.pci_dma_dev_setup = cell_pci_dma_dev_setup; + ppc_md.dma_get_required_mask = cell_dma_get_required_mask; ppc_md.tce_build = tce_build_cell; ppc_md.tce_free = tce_free_cell; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 01faab9456ca..fe5ededf0d60 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -1077,12 +1077,38 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) return 0; } +static u64 dma_get_required_mask_pSeriesLP(struct device *dev) +{ + if (!dev->dma_mask) + return 0; + + if (!disable_ddw && dev_is_pci(dev)) { + struct pci_dev *pdev = to_pci_dev(dev); + struct device_node *dn; + + dn = pci_device_to_OF_node(pdev); + + /* search upwards for ibm,dma-window */ + for (; dn && PCI_DN(dn) && !PCI_DN(dn)->iommu_table; + dn = dn->parent) + if (of_get_property(dn, "ibm,dma-window", NULL)) + break; + /* if there is a ibm,ddw-applicable property require 64 bits */ + if (dn && PCI_DN(dn) && + of_get_property(dn, "ibm,ddw-applicable", NULL)) + return DMA_BIT_MASK(64); + } + + return dma_iommu_get_required_mask(dev); +} + #else /* CONFIG_PCI */ #define pci_dma_bus_setup_pSeries NULL #define pci_dma_dev_setup_pSeries NULL #define pci_dma_bus_setup_pSeriesLP NULL #define pci_dma_dev_setup_pSeriesLP NULL #define dma_set_mask_pSeriesLP NULL +#define dma_get_required_mask_pSeriesLP NULL #endif /* !CONFIG_PCI */ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, @@ -1186,6 +1212,7 @@ void iommu_init_early_pSeries(void) ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP; ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP; ppc_md.dma_set_mask = dma_set_mask_pSeriesLP; + ppc_md.dma_get_required_mask = dma_get_required_mask_pSeriesLP; } else { ppc_md.tce_build = tce_build_pSeries; ppc_md.tce_free = tce_free_pSeries; From 89de9f65429a97ab627310e2e85426dcbe423f39 Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Mon, 29 Aug 2011 13:33:32 +0200 Subject: [PATCH 0133/1596] dmaengine/ste_dma40: add missing kernel doc for pending_queue Signed-off-by: Per Forlin Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index cd3a7c726bf8..486b6c0b44e3 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -174,6 +174,7 @@ struct d40_base; * @tasklet: Tasklet that gets scheduled from interrupt context to complete a * transfer and call client callback. * @client: Cliented owned descriptor list. + * @pending_queue: Submitted jobs, to be issued by issue_pending() * @active: Active descriptor. * @queue: Queued jobs. * @dma_cfg: The client configuration of this dma channel. From 270e779036ff144d6c6904ce9480f0d70ff93e86 Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Mon, 29 Aug 2011 13:33:33 +0200 Subject: [PATCH 0134/1596] dmaengine/ste_dma40: remove duplicate call to d40_pool_lli_free(). d40_desc_free() already calls d40_pool_lli_free(). Signed-off-by: Per Forlin Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 486b6c0b44e3..37388d10497a 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -478,7 +478,6 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c) list_for_each_entry_safe(d, _d, &d40c->client, node) if (async_tx_test_ack(&d->txd)) { - d40_pool_lli_free(d40c, d); d40_desc_remove(d); desc = d; memset(desc, 0, sizeof(*desc)); @@ -1209,7 +1208,6 @@ static void dma_tasklet(unsigned long data) if (!d40d->cyclic) { if (async_tx_test_ack(&d40d->txd)) { - d40_pool_lli_free(d40c, d40d); d40_desc_remove(d40d); d40_desc_free(d40c, d40d); } else { @@ -1606,7 +1604,6 @@ static int d40_free_dma(struct d40_chan *d40c) /* Release client owned descriptors */ if (!list_empty(&d40c->client)) list_for_each_entry_safe(d, _d, &d40c->client, node) { - d40_pool_lli_free(d40c, d); d40_desc_remove(d); d40_desc_free(d40c, d); } From 70a207ad4db2f0c60308b3f32086263c438c67a3 Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Mon, 29 Aug 2011 13:33:34 +0200 Subject: [PATCH 0135/1596] dmaengine/ste_dma40: fix Oops due to double free of client descriptor The client list may exist in two lists at the same time. This makes free fail since the same desc is freed multiple times. Remove desc from client list when adding it to the pending queue. Move free of client owned descriptors from free_dma() to terminate_all(). Unable to handle kernel paging request at virtual address 00100104 pgd = dea8c000 [00100104] *pgd=1ea62831, *pte=00000000, *ppte=00000000 Internal error: Oops: 817 [#1] PREEMPT SMP Modules linked in: CPU: 0 Not tainted (3.1.0-rc3+ #58) PC is at d40_free_chan_resources+0x64/0x330 Signed-off-by: Per Forlin Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 37388d10497a..92ec0a26401a 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -644,8 +644,11 @@ static struct d40_desc *d40_first_active_get(struct d40_chan *d40c) return d; } +/* remove desc from current queue and add it to the pending_queue */ static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc) { + d40_desc_remove(desc); + desc->is_in_client_list = false; list_add_tail(&desc->node, &d40c->pending_queue); } @@ -803,6 +806,7 @@ static int d40_channel_execute_command(struct d40_chan *d40c, static void d40_term_all(struct d40_chan *d40c) { struct d40_desc *d40d; + struct d40_desc *_d; /* Release active descriptors */ while ((d40d = d40_first_active_get(d40c))) { @@ -822,6 +826,14 @@ static void d40_term_all(struct d40_chan *d40c) d40_desc_free(d40c, d40d); } + /* Release client owned descriptors */ + if (!list_empty(&d40c->client)) + list_for_each_entry_safe(d40d, _d, &d40c->client, node) { + d40_desc_remove(d40d); + d40_desc_free(d40c, d40d); + } + + d40c->pending_tx = 0; d40c->busy = false; } @@ -1594,20 +1606,10 @@ static int d40_free_dma(struct d40_chan *d40c) u32 event; struct d40_phy_res *phy = d40c->phy_chan; bool is_src; - struct d40_desc *d; - struct d40_desc *_d; - /* Terminate all queued and active transfers */ d40_term_all(d40c); - /* Release client owned descriptors */ - if (!list_empty(&d40c->client)) - list_for_each_entry_safe(d, _d, &d40c->client, node) { - d40_desc_remove(d); - d40_desc_free(d40c, d); - } - if (phy == NULL) { chan_err(d40c, "phy == null\n"); return -EINVAL; From 503473ac2a3952e6af254b0769fe788a67d797e5 Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Mon, 29 Aug 2011 13:33:35 +0200 Subject: [PATCH 0136/1596] dmaengine/ste_dma40: fix memory leak due to prepared descriptors Prepared descriptors that are not submitted will not be freed. Add prepared descriptor to a list to be able to release them upon dmaengine_terminate_all(). Signed-off-by: Per Forlin Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 92ec0a26401a..467e4dcb20a0 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -177,6 +177,7 @@ struct d40_base; * @pending_queue: Submitted jobs, to be issued by issue_pending() * @active: Active descriptor. * @queue: Queued jobs. + * @prepare_queue: Prepared jobs. * @dma_cfg: The client configuration of this dma channel. * @configured: whether the dma_cfg configuration is valid * @base: Pointer to the device instance struct. @@ -204,6 +205,7 @@ struct d40_chan { struct list_head pending_queue; struct list_head active; struct list_head queue; + struct list_head prepare_queue; struct stedma40_chan_cfg dma_cfg; bool configured; struct d40_base *base; @@ -833,6 +835,13 @@ static void d40_term_all(struct d40_chan *d40c) d40_desc_free(d40c, d40d); } + /* Release descriptors in prepare queue */ + if (!list_empty(&d40c->prepare_queue)) + list_for_each_entry_safe(d40d, _d, + &d40c->prepare_queue, node) { + d40_desc_remove(d40d); + d40_desc_free(d40c, d40d); + } d40c->pending_tx = 0; d40c->busy = false; @@ -1911,6 +1920,12 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, goto err; } + /* + * add descriptor to the prepare queue in order to be able + * to free them later in terminate_all + */ + list_add_tail(&desc->node, &chan->prepare_queue); + spin_unlock_irqrestore(&chan->lock, flags); return &desc->txd; @@ -2400,6 +2415,7 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma, INIT_LIST_HEAD(&d40c->queue); INIT_LIST_HEAD(&d40c->pending_queue); INIT_LIST_HEAD(&d40c->client); + INIT_LIST_HEAD(&d40c->prepare_queue); tasklet_init(&d40c->tasklet, dma_tasklet, (unsigned long) d40c); From 7703eac96abd119dcfbb04f287a5127462d18269 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Wed, 31 Aug 2011 09:34:35 +0100 Subject: [PATCH 0137/1596] dmaengine: amba-pl08x: make filter check that the channel is owned by pl08x Before converting the dma channel to our private data structure, first check that the channel is indeed one which our driver registered. We do this by ensuring that the underlying device is bound to our driver. This avoids potential oopses if we try to reference 'plchan->name' against a foreign drivers dma channel. Signed-off-by: Russell King Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 3c2cad5b1165..cd8df7f5b5c8 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -87,6 +87,8 @@ #define DRIVER_NAME "pl08xdmac" +static struct amba_driver pl08x_amba_driver; + /** * struct vendor_data - vendor-specific config parameters for PL08x derivatives * @channels: the number of channels available in this variant @@ -1420,9 +1422,15 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) { - struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); + struct pl08x_dma_chan *plchan; char *name = chan_id; + /* Reject channels for devices not bound to this driver */ + if (chan->device->dev->driver != &pl08x_amba_driver.drv) + return false; + + plchan = to_pl08x_chan(chan); + /* Check that the channel is not taken! */ if (!strcmp(plchan->name, name)) return true; From 6a5be57f0f00bf5f39b983ec98d58058bc696543 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Mon, 1 Aug 2011 09:51:24 -0400 Subject: [PATCH 0138/1596] fixdep: fix extraneous dependencies The introduction of include/linux/kconfig.h created 3 extraneous dependencies: include/config/.h include/config/h.h include/config/foo.h Fix this by excluding kconfig.h from fixdep calculations. Signed-off-by: Peter Foley Signed-off-by: Michal Marek --- scripts/basic/fixdep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 291228e25984..cb1f50cf12e3 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -345,6 +345,7 @@ static void parse_dep_file(void *map, size_t len) memcpy(s, m, p-m); s[p-m] = 0; if (strrcmp(s, "include/generated/autoconf.h") && strrcmp(s, "arch/um/include/uml-config.h") && + strrcmp(s, "include/linux/kconfig.h") && strrcmp(s, ".ver")) { /* * Do not list the source file as dependency, so that From cd96ea3a4f2c9c226216c8d8e57fd8f86801515d Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Wed, 17 Aug 2011 15:10:52 +0800 Subject: [PATCH 0139/1596] Makefile: remove a duplicated line There are two duplicated lines for 'make RECORDMCOUNT_WARN=1 [targets]' in 'make help', remove the second one. Signed-off-by: WANG Cong Signed-off-by: Michal Marek --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index d714838d0a3a..ab38311014e6 100644 --- a/Makefile +++ b/Makefile @@ -1296,7 +1296,6 @@ help: @echo ' 2: warnings which occur quite often but may still be relevant' @echo ' 3: more obscure warnings, can most likely be ignored' @echo ' Multiple levels can be combined with W=12 or W=123' - @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' @echo '' @echo 'Execute "make" or "make all" to build all targets marked with [*] ' @echo 'For further info see the ./README file' From 4e24dbfc26f8b8285c9ed2f92ffddf4eb8ab960a Mon Sep 17 00:00:00 2001 From: Cheng Renquan Date: Thu, 1 Sep 2011 10:52:18 -0700 Subject: [PATCH 0140/1596] scripts/kconfig/nconf: fix typo: unknow => unknown Signed-off-by: Cheng Renquan Acked-by: Arnaud Lacombe --- scripts/kconfig/nconf.gui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index f8137b3a5382..d3af04e95288 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -461,7 +461,7 @@ int dialog_inputbox(WINDOW *main_window, result[cursor_position] = res; cursor_position++; } else { - mvprintw(0, 0, "unknow key: %d\n", res); + mvprintw(0, 0, "unknown key: %d\n", res); } break; } From cd58a90fa6ff2ec86bcc9e399acfd6dcc97268b3 Mon Sep 17 00:00:00 2001 From: Cheng Renquan Date: Thu, 1 Sep 2011 10:52:19 -0700 Subject: [PATCH 0141/1596] scripts/kconfig/nconf: fix memmove's length arg In case KEY_BACKSPACE / KEY_DC to delete a char, it memmove only (len-cursor_position+1) bytes; the default case is to insert a char, it should also memmove exactly (len-cursor_position+1) bytes; the original use of (len+1) is wrong and may access following memory that doesn't belong to result, may cause SegFault in theory; case KEY_BACKSPACE: if (cursor_position > 0) { memmove(&result[cursor_position-1], &result[cursor_position], len-cursor_position+1); cursor_position--; } break; case KEY_DC: if (cursor_position >= 0 && cursor_position < len) { memmove(&result[cursor_position], &result[cursor_position+1], len-cursor_position+1); } break; default: if ((isgraph(res) || isspace(res)) && len-2 < result_len) { /* insert the char at the proper position */ memmove(&result[cursor_position+1], &result[cursor_position], len-cursor_position+1); result[cursor_position] = res; cursor_position++; } Signed-off-by: Cheng Renquan Acked-by: Nir Tzachar --- scripts/kconfig/nconf.gui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index d3af04e95288..3ce2a7c0bda6 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -457,7 +457,7 @@ int dialog_inputbox(WINDOW *main_window, /* insert the char at the proper position */ memmove(&result[cursor_position+1], &result[cursor_position], - len+1); + len-cursor_position+1); result[cursor_position] = res; cursor_position++; } else { From 5ea9f64ffc073bf2882f6aa83b0dad3609b1e67a Mon Sep 17 00:00:00 2001 From: Cheng Renquan Date: Thu, 1 Sep 2011 10:52:20 -0700 Subject: [PATCH 0142/1596] scripts/kconfig/nconf: dynamically alloc dialog_input_result To support unlimited length string config items; No check for realloc return value keeps code simple, and to be consistent with other existing unchecked malloc in kconfig. Signed-off-by: Cheng Renquan Signed-off-by: Arnaud Lacombe --- scripts/kconfig/nconf.c | 21 ++++++++++----------- scripts/kconfig/nconf.gui.c | 20 +++++++++++++++----- scripts/kconfig/nconf.h | 2 +- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index b113c50209e3..73070cb0b6de 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -278,6 +278,9 @@ static int global_exit; /* the currently selected button */ const char *current_instructions = menu_instructions; +static char *dialog_input_result; +static int dialog_input_result_len; + static void conf(struct menu *menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); @@ -693,7 +696,6 @@ static void search_conf(void) { struct symbol **sym_arr; struct gstr res; - char dialog_input_result[100]; char *dialog_input; int dres; again: @@ -701,7 +703,7 @@ static void search_conf(void) _("Search Configuration Parameter"), _("Enter " CONFIG_ " (sub)string to search for " "(with or without \"" CONFIG_ "\")"), - "", dialog_input_result, 99); + "", &dialog_input_result, &dialog_input_result_len); switch (dres) { case 0: break; @@ -1346,7 +1348,6 @@ static void conf_choice(struct menu *menu) static void conf_string(struct menu *menu) { const char *prompt = menu_get_prompt(menu); - char dialog_input_result[256]; while (1) { int res; @@ -1369,8 +1370,8 @@ static void conf_string(struct menu *menu) prompt ? _(prompt) : _("Main Menu"), heading, sym_get_string_value(menu->sym), - dialog_input_result, - sizeof(dialog_input_result)); + &dialog_input_result, + &dialog_input_result_len); switch (res) { case 0: if (sym_set_string_value(menu->sym, @@ -1390,14 +1391,13 @@ static void conf_string(struct menu *menu) static void conf_load(void) { - char dialog_input_result[256]; while (1) { int res; res = dialog_inputbox(main_window, NULL, load_config_text, filename, - dialog_input_result, - sizeof(dialog_input_result)); + &dialog_input_result, + &dialog_input_result_len); switch (res) { case 0: if (!dialog_input_result[0]) @@ -1422,14 +1422,13 @@ static void conf_load(void) static void conf_save(void) { - char dialog_input_result[256]; while (1) { int res; res = dialog_inputbox(main_window, NULL, save_config_text, filename, - dialog_input_result, - sizeof(dialog_input_result)); + &dialog_input_result, + &dialog_input_result_len); switch (res) { case 0: if (!dialog_input_result[0]) diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 3ce2a7c0bda6..d64bc1c24c20 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -356,7 +356,7 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...) int dialog_inputbox(WINDOW *main_window, const char *title, const char *prompt, - const char *init, char *result, int result_len) + const char *init, char **resultp, int *result_len) { int prompt_lines = 0; int prompt_width = 0; @@ -367,7 +367,12 @@ int dialog_inputbox(WINDOW *main_window, int i, x, y; int res = -1; int cursor_position = strlen(init); + char *result = *resultp; + if (strlen(init)+1 > *result_len) { + *result_len = strlen(init)+1; + *resultp = result = realloc(result, *result_len); + } /* find the widest line of msg: */ prompt_lines = get_line_no(prompt); @@ -384,7 +389,7 @@ int dialog_inputbox(WINDOW *main_window, y = (LINES-(prompt_lines+4))/2; x = (COLS-(prompt_width+4))/2; - strncpy(result, init, result_len); + strncpy(result, init, *result_len); /* create the windows */ win = newwin(prompt_lines+6, prompt_width+7, y, x); @@ -443,7 +448,7 @@ int dialog_inputbox(WINDOW *main_window, case KEY_UP: case KEY_RIGHT: if (cursor_position < len && - cursor_position < min(result_len, prompt_width)) + cursor_position < min(*result_len, prompt_width)) cursor_position++; break; case KEY_DOWN: @@ -452,8 +457,13 @@ int dialog_inputbox(WINDOW *main_window, cursor_position--; break; default: - if ((isgraph(res) || isspace(res)) && - len-2 < result_len) { + if ((isgraph(res) || isspace(res))) { + /* one for new char, one for '\0' */ + if (len+2 > *result_len) { + *result_len = len+2; + *resultp = result = realloc(result, + *result_len); + } /* insert the char at the proper position */ memmove(&result[cursor_position+1], &result[cursor_position], diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h index 58fbda8fc0dc..0d5261705ef5 100644 --- a/scripts/kconfig/nconf.h +++ b/scripts/kconfig/nconf.h @@ -89,7 +89,7 @@ void fill_window(WINDOW *win, const char *text); int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...); int dialog_inputbox(WINDOW *main_window, const char *title, const char *prompt, - const char *init, char *result, int result_len); + const char *init, char **resultp, int *result_len); void refresh_all_windows(WINDOW *main_window); void show_scroll_win(WINDOW *main_window, const char *title, From e631a57a19e103c3bb59495b236634ec62e2a850 Mon Sep 17 00:00:00 2001 From: Cheng Renquan Date: Thu, 1 Sep 2011 10:52:21 -0700 Subject: [PATCH 0143/1596] scripts/kconfig/nconf: fix editing long strings The original dialog_inputbox doesn't work with longer than prompt_width strings, here fixed it in this way: 1) add variable cursor_form_win to record cursor of form_win, keep its value always between [0, prompt_width-1]; reuse the original cursor_position as cursor of the string result, use (cursor_position-cursor_form_win) as begin offset to show part of the string in form_win; Signed-off-by: Cheng Renquan Cc: Arnaud Lacombe Cc: Nir Tzachar --- scripts/kconfig/nconf.gui.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index d64bc1c24c20..4b9d8b66087d 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -367,6 +367,7 @@ int dialog_inputbox(WINDOW *main_window, int i, x, y; int res = -1; int cursor_position = strlen(init); + int cursor_form_win; char *result = *resultp; if (strlen(init)+1 > *result_len) { @@ -410,7 +411,9 @@ int dialog_inputbox(WINDOW *main_window, fill_window(prompt_win, prompt); mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); - mvwprintw(form_win, 0, 0, "%s", result); + cursor_form_win = min(cursor_position, prompt_width-1); + mvwprintw(form_win, 0, 0, "%s", + result + cursor_position-cursor_form_win); /* create panels */ panel = new_panel(win); @@ -436,6 +439,8 @@ int dialog_inputbox(WINDOW *main_window, &result[cursor_position], len-cursor_position+1); cursor_position--; + cursor_form_win--; + len--; } break; case KEY_DC: @@ -443,18 +448,22 @@ int dialog_inputbox(WINDOW *main_window, memmove(&result[cursor_position], &result[cursor_position+1], len-cursor_position+1); + len--; } break; case KEY_UP: case KEY_RIGHT: - if (cursor_position < len && - cursor_position < min(*result_len, prompt_width)) + if (cursor_position < len) { cursor_position++; + cursor_form_win++; + } break; case KEY_DOWN: case KEY_LEFT: - if (cursor_position > 0) + if (cursor_position > 0) { cursor_position--; + cursor_form_win--; + } break; default: if ((isgraph(res) || isspace(res))) { @@ -470,16 +479,24 @@ int dialog_inputbox(WINDOW *main_window, len-cursor_position+1); result[cursor_position] = res; cursor_position++; + cursor_form_win++; + len++; } else { mvprintw(0, 0, "unknown key: %d\n", res); } break; } + if (cursor_form_win < 0) + cursor_form_win = 0; + else if (cursor_form_win > prompt_width-1) + cursor_form_win = prompt_width-1; + wmove(form_win, 0, 0); wclrtoeol(form_win); mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); - mvwprintw(form_win, 0, 0, "%s", result); - wmove(form_win, 0, cursor_position); + mvwprintw(form_win, 0, 0, "%s", + result + cursor_position-cursor_form_win); + wmove(form_win, 0, cursor_form_win); touchwin(win); refresh_all_windows(main_window); From 93072c3ecafcf188390750cc755185f3150736b9 Mon Sep 17 00:00:00 2001 From: Cheng Renquan Date: Thu, 1 Sep 2011 10:52:22 -0700 Subject: [PATCH 0144/1596] scripts/kconfig/nconf: add KEY_HOME / KEY_END for dialog_inputbox to make it easier to locate begin/end when editing long strings; Signed-off-by: Cheng Renquan Acked By: Nir Tzachar --- scripts/kconfig/nconf.gui.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 4b9d8b66087d..3b18dd839668 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -465,6 +465,14 @@ int dialog_inputbox(WINDOW *main_window, cursor_form_win--; } break; + case KEY_HOME: + cursor_position = 0; + cursor_form_win = 0; + break; + case KEY_END: + cursor_position = len; + cursor_form_win = min(cursor_position, prompt_width-1); + break; default: if ((isgraph(res) || isspace(res))) { /* one for new char, one for '\0' */ From a0dc552951dcbb2b28a8a2ffb5fa966613e8c025 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 May 2011 16:31:20 -0700 Subject: [PATCH 0145/1596] mtd: nand: remove NAND_BBT_SCANBYTE1AND6 option This patch reverts most of: commit 58373ff0afff4cc8ac40608872995f4d87eb72ec mtd: nand: more BB Detection refactoring and dynamic scan options According to the discussion at: http://lists.infradead.org/pipermail/linux-mtd/2011-May/035696.html the NAND_BBT_SCANBYTE1AND6 flag, although technically valid, can break some existing ECC layouts that use the 6th byte in the OOB for ECC data. Furthermore, we apparently do not need to scan both bytes 1 and 6 in the OOB region of the devices under consideration; instead, we only need to scan one or the other. Thus, the NAND_BBT_SCANBYTE1AND6 flag is at best unnecessary and at worst a regression. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 24 +++++------------------- drivers/mtd/nand/nand_bbt.c | 32 +------------------------------- include/linux/mtd/bbm.h | 2 -- 3 files changed, 6 insertions(+), 52 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a46e9bb847bd..bb2e24b2d6c4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -410,10 +410,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) else { nand_get_device(chip, mtd, FL_WRITING); - /* Write to first two pages and to byte 1 and 6 if necessary. - * If we write to more than one location, the first error - * encountered quits the procedure. We write two bytes per - * location, so we dont have to mess with 16 bit access. + /* + * Write to first two pages if necessary. If we write to more + * than one location, the first error encountered quits the + * procedure. We write two bytes per location, so we dont have + * to mess with 16 bit access. */ do { chip->ops.len = chip->ops.ooblen = 2; @@ -423,11 +424,6 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) ret = nand_do_write_oob(mtd, ofs, &chip->ops); - if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) { - chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS - & ~0x01; - ret = nand_do_write_oob(mtd, ofs, &chip->ops); - } i++; ofs += mtd->writesize; } while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) && @@ -3131,16 +3127,6 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, *maf_id == NAND_MFR_MICRON)) chip->options |= NAND_BBT_SCAN2NDPAGE; - /* - * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6 - */ - if (!(busw & NAND_BUSWIDTH_16) && - *maf_id == NAND_MFR_STMICRO && - mtd->writesize == 2048) { - chip->options |= NAND_BBT_SCANBYTE1AND6; - chip->badblockpos = 0; - } - /* Check for AND chips with 4 page planes */ if (chip->options & NAND_4PAGE_ARRAY) chip->erase_cmd = multi_erase_cmd; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ccbeaa1e4a8e..5ffb9a4632ca 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -114,28 +114,6 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc return -1; } - /* Check both positions 1 and 6 for pattern? */ - if (td->options & NAND_BBT_SCANBYTE1AND6) { - if (td->options & NAND_BBT_SCANEMPTY) { - p += td->len; - end += NAND_SMALL_BADBLOCK_POS - td->offs; - /* Check region between positions 1 and 6 */ - for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; - i++) { - if (*p++ != 0xff) - return -1; - } - } - else { - p += NAND_SMALL_BADBLOCK_POS - td->offs; - } - /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } - } - if (td->options & NAND_BBT_SCANEMPTY) { p += td->len; end += td->len; @@ -167,13 +145,6 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) if (p[td->offs + i] != td->pattern[i]) return -1; } - /* Need to check location 1 AND 6? */ - if (td->options & NAND_BBT_SCANBYTE1AND6) { - for (i = 0; i < td->len; i++) { - if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) - return -1; - } - } return 0; } @@ -1330,8 +1301,7 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { .pattern = mirror_pattern }; -#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ - NAND_BBT_SCANBYTE1AND6) +#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE) /** * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure * @this: NAND chip to create descriptor for diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 57cc0e63714f..08ffa2193c07 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -98,8 +98,6 @@ struct nand_bbt_descr { #define NAND_BBT_SCAN2NDPAGE 0x00004000 /* Search good / bad pattern on the last page of the eraseblock */ #define NAND_BBT_SCANLASTPAGE 0x00008000 -/* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */ -#define NAND_BBT_SCANBYTE1AND6 0x00100000 /* The nand_bbt_descr was created dynamicaly and must be freed */ #define NAND_BBT_DYNAMICSTRUCT 0x00200000 /* The bad block table does not OOB for marker */ From 5fb1549dfc40f3b589dae560ea21535cdc5f64e0 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 May 2011 16:31:21 -0700 Subject: [PATCH 0146/1596] mtd: nand: separate chip options / bbt_options This patch handles the problems we've been having with using conflicting flags from nand.h and bbm.h in the same nand_chip.options field. We should try to separate these two spaces a little more clearly, and so I have added a bbt_options field to nand_chip. Important notes about nand_chip fields: * bbt_options field should contain ONLY flags from bbm.h. They should be able to pass safely to a nand_bbt_descr data structure. - BBT option flags start with the "NAND_BBT_" prefix. * options field should contian ONLY flags from nand.h. Ideally, they should not be involved in any BBT related options. - NAND chip option flags start with the "NAND_" prefix. * Every flag should have a nice comment explaining what the flag is. While this is not yet the case on all existing flags, please be sure to write one for new flags. Even better, you can help document the code better yourself! Please try to follow these conventions to make everyone's lives easier. Among the flags that are being moved to the new bbt_options field throughout various drivers, etc. are: * NAND_BBT_SCANLASTPAGE * NAND_BBT_SCAN2NDPAGE and there will be more to come. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 10 +++++----- drivers/mtd/nand/nand_bbt.c | 5 ++--- include/linux/mtd/nand.h | 4 ++++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bb2e24b2d6c4..3a9a8fc6a36c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -344,7 +344,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) struct nand_chip *chip = mtd->priv; u16 bad; - if (chip->options & NAND_BBT_SCANLASTPAGE) + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; page = (int)(ofs >> chip->page_shift) & chip->pagemask; @@ -396,7 +396,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) uint8_t buf[2] = { 0, 0 }; int block, ret, i = 0; - if (chip->options & NAND_BBT_SCANLASTPAGE) + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; /* Get block number */ @@ -426,7 +426,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) i++; ofs += mtd->writesize; - } while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) && + } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); nand_release_device(mtd); @@ -3117,7 +3117,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX)) - chip->options |= NAND_BBT_SCANLASTPAGE; + chip->bbt_options |= NAND_BBT_SCANLASTPAGE; else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX || @@ -3125,7 +3125,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, *maf_id == NAND_MFR_AMD)) || (mtd->writesize == 2048 && *maf_id == NAND_MFR_MICRON)) - chip->options |= NAND_BBT_SCAN2NDPAGE; + chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; /* Check for AND chips with 4 page planes */ if (chip->options & NAND_4PAGE_ARRAY) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5ffb9a4632ca..5df01d8efd92 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -517,7 +517,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, from = (loff_t)startblock << (this->bbt_erase_shift - 1); } - if (this->options & NAND_BBT_SCANLASTPAGE) + if (this->bbt_options & NAND_BBT_SCANLASTPAGE) from += mtd->erasesize - (mtd->writesize * len); for (i = startblock; i < numblocks;) { @@ -1301,7 +1301,6 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { .pattern = mirror_pattern }; -#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE) /** * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure * @this: NAND chip to create descriptor for @@ -1324,7 +1323,7 @@ static int nand_create_default_bbt_descr(struct nand_chip *this) printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); return -ENOMEM; } - bd->options = this->options & BBT_SCAN_OPTIONS; + bd->options = this->bbt_options; bd->offs = this->badblockpos; bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; bd->pattern = scan_ff_pattern; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c2b9ac4fbc4a..42f70e2d33af 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -449,6 +449,9 @@ struct nand_buffers { * @options: [BOARDSPECIFIC] various chip options. They can partly * be set to inform nand_scan about special functionality. * See the defines for further explanation. + * @bbt_options: [INTERN] bad block specific options. All options used + * here must come from bbm.h. By default, these options + * will be copied to the appropriate nand_bbt_descr's. * @badblockpos: [INTERN] position of the bad block marker in the oob * area. * @badblockbits: [INTERN] number of bits to left-shift the bad block @@ -509,6 +512,7 @@ struct nand_chip { int chip_delay; unsigned int options; + unsigned int bbt_options; int page_shift; int phys_erase_shift; From a40f73419f02e40555f692785ea1c1813d5b4c12 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 May 2011 16:31:22 -0700 Subject: [PATCH 0147/1596] mtd: nand: consolidate redundant flash-based BBT flags This patch works with the following three flags from two headers (nand.h and bbm.h): (1) NAND_USE_FLASH_BBT (nand.h) (2) NAND_USE_FLASH_BBT_NO_OOB (nand.h) (3) NAND_BBT_NO_OOB (bbm.h) These flags are all related and interdependent, yet they were in different headers. Flag (2) is simply the combination of (1) and (3) and can be eliminated. This patch accomplishes the following: * eliminate NAND_USE_FLASH_BBT_NO_OOB (i.e., flag (2)) * move NAND_USE_FLASH_BBT (i.e., flag (1)) to bbm.h It's important to note that because (1) and (3) are now both found in bbm.h, they should NOT be used in the "nand_chip.options" field. I removed a small section from the mtdnand DocBook because it referes to NAND_USE_FLASH_BBT in nand.h, which has been moved to bbm.h. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- Documentation/DocBook/mtdnand.tmpl | 5 +---- arch/arm/mach-davinci/board-da830-evm.c | 2 +- arch/arm/mach-davinci/board-da850-evm.c | 2 +- arch/arm/mach-davinci/board-dm355-evm.c | 2 +- arch/arm/mach-davinci/board-dm355-leopard.c | 2 +- arch/arm/mach-davinci/board-dm365-evm.c | 2 +- arch/arm/mach-davinci/board-dm644x-evm.c | 2 +- arch/arm/mach-davinci/board-mityomapl138.c | 3 ++- arch/arm/mach-davinci/board-neuros-osd2.c | 2 +- arch/arm/mach-davinci/board-tnetv107x-evm.c | 2 +- arch/arm/mach-davinci/include/mach/nand.h | 4 +++- arch/arm/mach-orion5x/ts78xx-setup.c | 2 +- .../cris/arch-v32/drivers/mach-a3/nandflash.c | 2 +- .../cris/arch-v32/drivers/mach-fs/nandflash.c | 2 +- drivers/mtd/nand/atmel_nand.c | 2 +- drivers/mtd/nand/autcpu12.c | 4 ++-- drivers/mtd/nand/bcm_umi_nand.c | 2 +- drivers/mtd/nand/cafe_nand.c | 3 ++- drivers/mtd/nand/cs553x_nand.c | 3 ++- drivers/mtd/nand/davinci_nand.c | 4 +++- drivers/mtd/nand/denali.c | 3 ++- drivers/mtd/nand/diskonchip.c | 2 +- drivers/mtd/nand/fsl_elbc_nand.c | 4 ++-- drivers/mtd/nand/mpc5121_nfc.c | 3 ++- drivers/mtd/nand/mxc_nand.c | 2 +- drivers/mtd/nand/nand_base.c | 2 +- drivers/mtd/nand/nand_bbt.c | 20 +++++++++---------- drivers/mtd/nand/nandsim.c | 4 ++-- drivers/mtd/nand/pasemi_nand.c | 3 ++- drivers/mtd/nand/plat_nand.c | 1 + drivers/mtd/nand/s3c2410.c | 6 ++++-- include/linux/mtd/bbm.h | 9 +++++++-- include/linux/mtd/nand.h | 12 ++--------- 33 files changed, 65 insertions(+), 58 deletions(-) diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index 17910e2052ad..05cc83ea8ef7 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -572,7 +572,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip) The simplest way to activate the FLASH based bad block table support - is to set the option NAND_USE_FLASH_BBT in the option field of + is to set the option NAND_USE_FLASH_BBT in the bbt_option field of the nand chip structure before calling nand_scan(). For AG-AND chips is this done by default. This activates the default FLASH based bad block table functionality @@ -1158,9 +1158,6 @@ in this page These constants are defined in nand.h. They are ored together to describe the functionality. -/* Use a flash based bad block table. This option is parsed by the - * default bad block table function (nand_default_bbt). */ -#define NAND_USE_FLASH_BBT 0x00010000 /* The hw ecc generator provides a syndrome instead a ecc value on read * This can only work if we have the ecc bytes directly behind the * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 84fd78684868..a790c1b363ff 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -377,7 +377,7 @@ static struct davinci_nand_pdata da830_evm_nand_pdata = { .nr_parts = ARRAY_SIZE(da830_evm_nand_partitions), .ecc_mode = NAND_ECC_HW, .ecc_bits = 4, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, .bbt_td = &da830_evm_nand_bbt_main_descr, .bbt_md = &da830_evm_nand_bbt_mirror_descr, .timing = &da830_evm_nandflash_timing, diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index bd5394537c88..de27111d1b27 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -225,7 +225,7 @@ static struct davinci_nand_pdata da850_evm_nandflash_data = { .nr_parts = ARRAY_SIZE(da850_evm_nandflash_partition), .ecc_mode = NAND_ECC_HW, .ecc_bits = 4, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, .timing = &da850_evm_nandflash_timing, }; diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 241a6bd67408..fd2de2c0338b 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -77,7 +77,7 @@ static struct davinci_nand_pdata davinci_nand_data = { .parts = davinci_nand_partitions, .nr_parts = ARRAY_SIZE(davinci_nand_partitions), .ecc_mode = NAND_ECC_HW, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, .ecc_bits = 4, }; diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index bee284ca7fd6..cfbd897e6611 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -74,7 +74,7 @@ static struct davinci_nand_pdata davinci_nand_data = { .parts = davinci_nand_partitions, .nr_parts = ARRAY_SIZE(davinci_nand_partitions), .ecc_mode = NAND_ECC_HW_SYNDROME, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, }; static struct resource davinci_nand_resources[] = { diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 9818f214d4f0..e66116ddea4f 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -139,7 +139,7 @@ static struct davinci_nand_pdata davinci_nand_data = { .parts = davinci_nand_partitions, .nr_parts = ARRAY_SIZE(davinci_nand_partitions), .ecc_mode = NAND_ECC_HW, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, .ecc_bits = 4, }; diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 95607a191e03..dde204933c9e 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -150,7 +150,7 @@ static struct davinci_nand_pdata davinci_evm_nandflash_data = { .parts = davinci_evm_nandflash_partition, .nr_parts = ARRAY_SIZE(davinci_evm_nandflash_partition), .ecc_mode = NAND_ECC_HW, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, .timing = &davinci_evm_nandflash_timing, }; diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index c278226627ad..ef7ba494493d 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -396,7 +396,8 @@ static struct davinci_nand_pdata mityomapl138_nandflash_data = { .parts = mityomapl138_nandflash_partition, .nr_parts = ARRAY_SIZE(mityomapl138_nandflash_partition), .ecc_mode = NAND_ECC_HW, - .options = NAND_USE_FLASH_BBT | NAND_BUSWIDTH_16, + .bbt_options = NAND_USE_FLASH_BBT, + .options = NAND_BUSWIDTH_16, .ecc_bits = 1, /* 4 bit mode is not supported with 16 bit NAND */ }; diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index d60a80028ba3..1989768973a7 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -87,7 +87,7 @@ static struct davinci_nand_pdata davinci_ntosd2_nandflash_data = { .parts = davinci_ntosd2_nandflash_partition, .nr_parts = ARRAY_SIZE(davinci_ntosd2_nandflash_partition), .ecc_mode = NAND_ECC_HW, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, }; static struct resource davinci_ntosd2_nandflash_resource[] = { diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index 782892065682..046f8e00938e 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -144,7 +144,7 @@ static struct davinci_nand_pdata nand_config = { .parts = nand_partitions, .nr_parts = ARRAY_SIZE(nand_partitions), .ecc_mode = NAND_ECC_HW, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, .ecc_bits = 1, }; diff --git a/arch/arm/mach-davinci/include/mach/nand.h b/arch/arm/mach-davinci/include/mach/nand.h index 025151049f05..2c506f905cb8 100644 --- a/arch/arm/mach-davinci/include/mach/nand.h +++ b/arch/arm/mach-davinci/include/mach/nand.h @@ -74,8 +74,10 @@ struct davinci_nand_pdata { /* platform_data */ nand_ecc_modes_t ecc_mode; u8 ecc_bits; - /* e.g. NAND_BUSWIDTH_16 or NAND_USE_FLASH_BBT */ + /* e.g. NAND_BUSWIDTH_16 */ unsigned options; + /* e.g. NAND_USE_FLASH_BBT */ + unsigned bbt_options; /* Main and mirror bbt descriptor overrides */ struct nand_bbt_descr *bbt_td; diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index 6b7b54116f30..e5ca57ce6e50 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -275,7 +275,7 @@ static struct platform_nand_data ts78xx_ts_nand_data = { .partitions = ts78xx_ts_nand_parts, .nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts), .chip_delay = 15, - .options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_USE_FLASH_BBT, }, .ctrl = { /* diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c index f58f2c1c5295..fdd11c12b759 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c @@ -163,7 +163,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void) this->ecc.mode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ - /* this->options = NAND_USE_FLASH_BBT; */ + /* this->bbt_options = NAND_USE_FLASH_BBT; */ /* Scan to find existence of the device */ if (nand_scan(crisv32_mtd, 1)) { diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c index d5b0cc9f976b..3368177bdd3b 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c @@ -154,7 +154,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void) this->ecc.mode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ - /* this->options = NAND_USE_FLASH_BBT; */ + /* this->bbt_options = NAND_USE_FLASH_BBT; */ /* Scan to find existence of the device */ if (nand_scan(crisv32_mtd, 1)) { diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 55da20ccc7a8..78d551622e11 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -583,7 +583,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if (on_flash_bbt) { printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); - nand_chip->options |= NAND_USE_FLASH_BBT; + nand_chip->bbt_options |= NAND_USE_FLASH_BBT; } if (!cpu_has_dma()) diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index eddc9a224985..adf934df8958 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -172,9 +172,9 @@ static int __init autcpu12_init(void) /* Enable the following for a flash based bad block table */ /* - this->options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_USE_FLASH_BBT; */ - this->options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_USE_FLASH_BBT; /* Scan to find existence of the device */ if (nand_scan(autcpu12_mtd, 1)) { diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 8c569e454dc5..974d9bc8e48e 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -474,7 +474,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) #if NAND_ECC_BCH if (board_mtd->writesize > 512) { - if (this->options & NAND_USE_FLASH_BBT) + if (this->bbt_options & NAND_USE_FLASH_BBT) largepage_bbt.options = NAND_BBT_SCAN2NDPAGE; this->badblock_pattern = &largepage_bbt; } diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 87ebb4e5b0c3..7dd7d844d2cf 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -686,7 +686,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe->nand.chip_delay = 0; /* Enable the following for a flash based bad block table */ - cafe->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; + cafe->nand.bbt_options = NAND_USE_FLASH_BBT; + cafe->nand.options = NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; if (skipbbt) { cafe->nand.options |= NAND_SKIP_BBTSCAN; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index f59ad1f2d5db..05adedd8c20c 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -239,7 +239,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this->ecc.correct = nand_correct_data; /* Enable the following for a flash based bad block table */ - this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; + this->bbt_options = NAND_USE_FLASH_BBT; + this->options = NAND_NO_AUTOINCR; /* Scan to find existence of the device */ if (nand_scan(new_mtd, 1)) { diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 1f34951ae1a7..69f70195ff35 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -581,7 +581,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.chip_delay = 0; info->chip.select_chip = nand_davinci_select_chip; - /* options such as NAND_USE_FLASH_BBT or 16-bit widths */ + /* options such as NAND_USE_FLASH_BBT */ + info->chip.bbt_options = pdata->bbt_options; + /* options such as 16-bit widths */ info->chip.options = pdata->options; info->chip.bbt_td = pdata->bbt_td; info->chip.bbt_md = pdata->bbt_md; diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d5276218945f..dbb6fbae7d25 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1577,7 +1577,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) denali->nand.bbt_md = &bbt_mirror_descr; /* skip the scan for now until we have OOB read and write support */ - denali->nand.options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; + denali->nand.bbt_options |= NAND_USE_FLASH_BBT; + denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; /* Denali Controller only support 15bit and 8bit ECC in MRST, diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 7837728d02ff..f70bc73e7948 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1652,7 +1652,7 @@ static int __init doc_probe(unsigned long physadr) nand->ecc.mode = NAND_ECC_HW_SYNDROME; nand->ecc.size = 512; nand->ecc.bytes = 6; - nand->options = NAND_USE_FLASH_BBT; + nand->bbt_options = NAND_USE_FLASH_BBT; doc->physadr = physadr; doc->virtadr = virtadr; diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 33d8aad8bba5..bff4791d73c3 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -791,8 +791,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->bbt_md = &bbt_mirror_descr; /* set up nand options */ - chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | - NAND_USE_FLASH_BBT; + chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; + chip->bbt_options = NAND_USE_FLASH_BBT; chip->controller = &elbc_fcm_ctrl->controller; chip->priv = priv; diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index eb1fbac63eb6..0ac64b54bd67 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -735,7 +735,8 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) chip->write_buf = mpc5121_nfc_write_buf; chip->verify_buf = mpc5121_nfc_verify_buf; chip->select_chip = mpc5121_nfc_select_chip; - chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; + chip->options = NAND_NO_AUTOINCR; + chip->bbt_options = NAND_USE_FLASH_BBT; chip->ecc.mode = NAND_ECC_SOFT; /* Support external chip-select logic on ADS5121 board */ diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 90df34c4d26c..ed68fde3d1be 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1179,7 +1179,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; /* update flash based bbt */ - this->options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_USE_FLASH_BBT; } init_completion(&host->op_completion); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 3a9a8fc6a36c..d39dffe71de4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -405,7 +405,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* Do we have a flash based bad block table ? */ - if (chip->options & NAND_USE_FLASH_BBT) + if (chip->bbt_options & NAND_USE_FLASH_BBT) ret = nand_update_bbt(mtd, ofs); else { nand_get_device(chip, mtd, FL_WRITING); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5df01d8efd92..66f93e2ac16b 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -36,9 +36,9 @@ * The table is marked in the OOB area with an ident pattern and a version * number which indicates which of both tables is more up to date. If the NAND * controller needs the complete OOB area for the ECC information then the - * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern - * and the version byte into the data area and the OOB area will remain - * untouched. + * option NAND_BBT_NO_OOB should be used (along with NAND_USE_FLASH_BBT, of + * course): it moves the ident pattern and the version byte into the data area + * and the OOB area will remain untouched. * * The table uses 2 bits per block * 11b: block is good @@ -1082,16 +1082,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) pattern_len = bd->len; bits = bd->options & NAND_BBT_NRBITS_MSK; - BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && - !(this->options & NAND_USE_FLASH_BBT)); + BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && + !(this->bbt_options & NAND_USE_FLASH_BBT)); BUG_ON(!bits); if (bd->options & NAND_BBT_VERSION) pattern_len++; if (bd->options & NAND_BBT_NO_OOB) { - BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); - BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); + BUG_ON(!(this->bbt_options & NAND_USE_FLASH_BBT)); + BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); BUG_ON(bd->offs); if (bd->options & NAND_BBT_VERSION) BUG_ON(bd->veroffs != bd->len); @@ -1357,15 +1357,15 @@ int nand_default_bbt(struct mtd_info *mtd) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } - this->options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_USE_FLASH_BBT; return nand_scan_bbt(mtd, &agand_flashbased); } /* Is a flash based bad block table requested ? */ - if (this->options & NAND_USE_FLASH_BBT) { + if (this->bbt_options & NAND_USE_FLASH_BBT) { /* Use the default pattern descriptors */ if (!this->bbt_td) { - if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { + if (this->bbt_options & NAND_BBT_NO_OOB) { this->bbt_td = &bbt_main_no_bbt_descr; this->bbt_md = &bbt_mirror_no_bbt_descr; } else { diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 357e8c5252a8..1856c42c62c4 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -2273,9 +2273,9 @@ static int __init ns_init_module(void) switch (bbt) { case 2: - chip->options |= NAND_USE_FLASH_BBT_NO_OOB; + chip->bbt_options |= NAND_BBT_NO_OOB; case 1: - chip->options |= NAND_USE_FLASH_BBT; + chip->bbt_options |= NAND_USE_FLASH_BBT; case 0: break; default: diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index b1aa41b8a4eb..1c17f091e16b 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -155,7 +155,8 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev) chip->ecc.mode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ - chip->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; + chip->options = NAND_NO_AUTOINCR; + chip->bbt_options = NAND_USE_FLASH_BBT; /* Scan to find existence of the device */ if (nand_scan(pasemi_nand_mtd, 1)) { diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 633c04bf76f6..ccdb16ec8143 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -79,6 +79,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) data->chip.read_buf = pdata->ctrl.read_buf; data->chip.chip_delay = pdata->chip.chip_delay; data->chip.options |= pdata->chip.options; + data->chip.bbt_options |= pdata->chip.bbt_options; data->chip.ecc.hwctl = pdata->ctrl.hwcontrol; data->chip.ecc.layout = pdata->chip.ecclayout; diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 4405468f196b..370516c3f7c7 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -880,8 +880,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, /* If you use u-boot BBT creation code, specifying this flag will * let the kernel fish out the BBT from the NAND, and also skip the * full NAND scan that can take 1/2s or so. Little things... */ - if (set->flash_bbt) - chip->options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; + if (set->flash_bbt) { + chip->bbt_options |= NAND_USE_FLASH_BBT; + chip->options |= NAND_SKIP_BBTSCAN; + } } /** diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 08ffa2193c07..7929514781ea 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -100,8 +100,13 @@ struct nand_bbt_descr { #define NAND_BBT_SCANLASTPAGE 0x00008000 /* The nand_bbt_descr was created dynamicaly and must be freed */ #define NAND_BBT_DYNAMICSTRUCT 0x00200000 -/* The bad block table does not OOB for marker */ -#define NAND_BBT_NO_OOB 0x00400000 +/* + * Use a flash based bad block table. By default, OOB identifier is saved in + * OOB area. This option is passed to the default bad block table function. + */ +#define NAND_USE_FLASH_BBT 0x00040000 +/* Do not store flash based bad block table in OOB area; store it in-band */ +#define NAND_BBT_NO_OOB 0x00080000 /* The maximum number of blocks to scan for a bbt */ #define NAND_BBT_SCAN_MAXBLOCKS 4 diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 42f70e2d33af..8a086d2cacf4 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -219,11 +219,6 @@ typedef enum { #define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) /* Non chip related options */ -/* - * Use a flash based bad block table. OOB identifier is saved in OOB area. - * This option is passed to the default bad block table function. - */ -#define NAND_USE_FLASH_BBT 0x00010000 /* This option skips the bbt scan during initialization. */ #define NAND_SKIP_BBTSCAN 0x00020000 /* @@ -233,11 +228,6 @@ typedef enum { #define NAND_OWN_BUFFERS 0x00040000 /* Chip may not exist, so silence any errors in scan */ #define NAND_SCAN_SILENT_NODEV 0x00080000 -/* - * If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch - * the OOB area. - */ -#define NAND_USE_FLASH_BBT_NO_OOB 0x00800000 /* Create an empty BBT with no vendor information if the BBT is available */ #define NAND_CREATE_EMPTY_BBT 0x01000000 @@ -615,6 +605,7 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, * @partitions: mtd partition list * @chip_delay: R/B delay value in us * @options: Option flags, e.g. 16bit buswidth + * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH * @ecclayout: ecc layout info structure * @part_probe_types: NULL-terminated array of probe types * @set_parts: platform specific function to set partitions @@ -628,6 +619,7 @@ struct platform_nand_chip { struct nand_ecclayout *ecclayout; int chip_delay; unsigned int options; + unsigned int bbt_options; const char **part_probe_types; void (*set_parts)(uint64_t size, struct platform_nand_chip *chip); void *priv; From bb9ebd4e714385a2592a482845865ef2d58b2868 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 May 2011 16:31:23 -0700 Subject: [PATCH 0148/1596] mtd: nand: rename NAND_USE_FLASH_BBT Recall the recently added prefix requirements: * "NAND_" for flags in nand.h, used in nand_chip.options * "NAND_BBT_" for flags in bbm.h, used in nand_chip.bbt_options or in nand_bbt_descr.options Thus, I am changing NAND_USE_FLASH_BBT to NAND_BBT_USE_FLASH. Again, this flag is found in bbm.h and so should NOT be used in the "nand_chip.options" field. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- Documentation/DocBook/mtdnand.tmpl | 2 +- arch/arm/mach-davinci/board-da830-evm.c | 2 +- arch/arm/mach-davinci/board-da850-evm.c | 2 +- arch/arm/mach-davinci/board-dm355-evm.c | 2 +- arch/arm/mach-davinci/board-dm355-leopard.c | 2 +- arch/arm/mach-davinci/board-dm365-evm.c | 2 +- arch/arm/mach-davinci/board-dm644x-evm.c | 2 +- arch/arm/mach-davinci/board-mityomapl138.c | 2 +- arch/arm/mach-davinci/board-neuros-osd2.c | 2 +- arch/arm/mach-davinci/board-tnetv107x-evm.c | 2 +- arch/arm/mach-davinci/include/mach/nand.h | 2 +- arch/arm/mach-orion5x/ts78xx-setup.c | 2 +- arch/cris/arch-v32/drivers/mach-a3/nandflash.c | 2 +- arch/cris/arch-v32/drivers/mach-fs/nandflash.c | 2 +- drivers/mtd/nand/atmel_nand.c | 2 +- drivers/mtd/nand/autcpu12.c | 4 ++-- drivers/mtd/nand/bcm_umi_nand.c | 2 +- drivers/mtd/nand/cafe_nand.c | 2 +- drivers/mtd/nand/cs553x_nand.c | 2 +- drivers/mtd/nand/davinci_nand.c | 2 +- drivers/mtd/nand/denali.c | 2 +- drivers/mtd/nand/diskonchip.c | 2 +- drivers/mtd/nand/fsl_elbc_nand.c | 2 +- drivers/mtd/nand/mpc5121_nfc.c | 2 +- drivers/mtd/nand/mxc_nand.c | 2 +- drivers/mtd/nand/nand_base.c | 2 +- drivers/mtd/nand/nand_bbt.c | 12 ++++++------ drivers/mtd/nand/nandsim.c | 2 +- drivers/mtd/nand/pasemi_nand.c | 2 +- drivers/mtd/nand/s3c2410.c | 2 +- include/linux/mtd/bbm.h | 2 +- 31 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index 05cc83ea8ef7..8c07540c181c 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -572,7 +572,7 @@ static void board_select_chip (struct mtd_info *mtd, int chip) The simplest way to activate the FLASH based bad block table support - is to set the option NAND_USE_FLASH_BBT in the bbt_option field of + is to set the option NAND_BBT_USE_FLASH in the bbt_option field of the nand chip structure before calling nand_scan(). For AG-AND chips is this done by default. This activates the default FLASH based bad block table functionality diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index a790c1b363ff..0b36fd54fc47 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -377,7 +377,7 @@ static struct davinci_nand_pdata da830_evm_nand_pdata = { .nr_parts = ARRAY_SIZE(da830_evm_nand_partitions), .ecc_mode = NAND_ECC_HW, .ecc_bits = 4, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, .bbt_td = &da830_evm_nand_bbt_main_descr, .bbt_md = &da830_evm_nand_bbt_mirror_descr, .timing = &da830_evm_nandflash_timing, diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index de27111d1b27..8193d340de22 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -225,7 +225,7 @@ static struct davinci_nand_pdata da850_evm_nandflash_data = { .nr_parts = ARRAY_SIZE(da850_evm_nandflash_partition), .ecc_mode = NAND_ECC_HW, .ecc_bits = 4, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, .timing = &da850_evm_nandflash_timing, }; diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index fd2de2c0338b..fe617790fe2b 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -77,7 +77,7 @@ static struct davinci_nand_pdata davinci_nand_data = { .parts = davinci_nand_partitions, .nr_parts = ARRAY_SIZE(davinci_nand_partitions), .ecc_mode = NAND_ECC_HW, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, .ecc_bits = 4, }; diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index cfbd897e6611..249c35512748 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -74,7 +74,7 @@ static struct davinci_nand_pdata davinci_nand_data = { .parts = davinci_nand_partitions, .nr_parts = ARRAY_SIZE(davinci_nand_partitions), .ecc_mode = NAND_ECC_HW_SYNDROME, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, }; static struct resource davinci_nand_resources[] = { diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index e66116ddea4f..e555267f2492 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -139,7 +139,7 @@ static struct davinci_nand_pdata davinci_nand_data = { .parts = davinci_nand_partitions, .nr_parts = ARRAY_SIZE(davinci_nand_partitions), .ecc_mode = NAND_ECC_HW, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, .ecc_bits = 4, }; diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index dde204933c9e..8fd305264e83 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -150,7 +150,7 @@ static struct davinci_nand_pdata davinci_evm_nandflash_data = { .parts = davinci_evm_nandflash_partition, .nr_parts = ARRAY_SIZE(davinci_evm_nandflash_partition), .ecc_mode = NAND_ECC_HW, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, .timing = &davinci_evm_nandflash_timing, }; diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index ef7ba494493d..dffab31670f7 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -396,7 +396,7 @@ static struct davinci_nand_pdata mityomapl138_nandflash_data = { .parts = mityomapl138_nandflash_partition, .nr_parts = ARRAY_SIZE(mityomapl138_nandflash_partition), .ecc_mode = NAND_ECC_HW, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, .options = NAND_BUSWIDTH_16, .ecc_bits = 1, /* 4 bit mode is not supported with 16 bit NAND */ }; diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index 1989768973a7..70dcf9f30213 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -87,7 +87,7 @@ static struct davinci_nand_pdata davinci_ntosd2_nandflash_data = { .parts = davinci_ntosd2_nandflash_partition, .nr_parts = ARRAY_SIZE(davinci_ntosd2_nandflash_partition), .ecc_mode = NAND_ECC_HW, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, }; static struct resource davinci_ntosd2_nandflash_resource[] = { diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index 046f8e00938e..75383df868ff 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -144,7 +144,7 @@ static struct davinci_nand_pdata nand_config = { .parts = nand_partitions, .nr_parts = ARRAY_SIZE(nand_partitions), .ecc_mode = NAND_ECC_HW, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, .ecc_bits = 1, }; diff --git a/arch/arm/mach-davinci/include/mach/nand.h b/arch/arm/mach-davinci/include/mach/nand.h index 2c506f905cb8..1cf555aef896 100644 --- a/arch/arm/mach-davinci/include/mach/nand.h +++ b/arch/arm/mach-davinci/include/mach/nand.h @@ -76,7 +76,7 @@ struct davinci_nand_pdata { /* platform_data */ /* e.g. NAND_BUSWIDTH_16 */ unsigned options; - /* e.g. NAND_USE_FLASH_BBT */ + /* e.g. NAND_BBT_USE_FLASH */ unsigned bbt_options; /* Main and mirror bbt descriptor overrides */ diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index e5ca57ce6e50..8ae53015eeb8 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -275,7 +275,7 @@ static struct platform_nand_data ts78xx_ts_nand_data = { .partitions = ts78xx_ts_nand_parts, .nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts), .chip_delay = 15, - .bbt_options = NAND_USE_FLASH_BBT, + .bbt_options = NAND_BBT_USE_FLASH, }, .ctrl = { /* diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c index fdd11c12b759..7fb52128ddc9 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c @@ -163,7 +163,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void) this->ecc.mode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ - /* this->bbt_options = NAND_USE_FLASH_BBT; */ + /* this->bbt_options = NAND_BBT_USE_FLASH; */ /* Scan to find existence of the device */ if (nand_scan(crisv32_mtd, 1)) { diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c index 3368177bdd3b..e03238454b0e 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c @@ -154,7 +154,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void) this->ecc.mode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ - /* this->bbt_options = NAND_USE_FLASH_BBT; */ + /* this->bbt_options = NAND_BBT_USE_FLASH; */ /* Scan to find existence of the device */ if (nand_scan(crisv32_mtd, 1)) { diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 78d551622e11..79a7ef276616 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -583,7 +583,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if (on_flash_bbt) { printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); - nand_chip->bbt_options |= NAND_USE_FLASH_BBT; + nand_chip->bbt_options |= NAND_BBT_USE_FLASH; } if (!cpu_has_dma()) diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index adf934df8958..2e42ec2e8ff4 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -172,9 +172,9 @@ static int __init autcpu12_init(void) /* Enable the following for a flash based bad block table */ /* - this->bbt_options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_BBT_USE_FLASH; */ - this->bbt_options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ if (nand_scan(autcpu12_mtd, 1)) { diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 974d9bc8e48e..e3ffc4c908e4 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -474,7 +474,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) #if NAND_ECC_BCH if (board_mtd->writesize > 512) { - if (this->bbt_options & NAND_USE_FLASH_BBT) + if (this->bbt_options & NAND_BBT_USE_FLASH) largepage_bbt.options = NAND_BBT_SCAN2NDPAGE; this->badblock_pattern = &largepage_bbt; } diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 7dd7d844d2cf..d0eed498ed2b 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -686,7 +686,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe->nand.chip_delay = 0; /* Enable the following for a flash based bad block table */ - cafe->nand.bbt_options = NAND_USE_FLASH_BBT; + cafe->nand.bbt_options = NAND_BBT_USE_FLASH; cafe->nand.options = NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; if (skipbbt) { diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 05adedd8c20c..b35496143e74 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -239,7 +239,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this->ecc.correct = nand_correct_data; /* Enable the following for a flash based bad block table */ - this->bbt_options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_BBT_USE_FLASH; this->options = NAND_NO_AUTOINCR; /* Scan to find existence of the device */ diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 69f70195ff35..a4c82b4344ba 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -581,7 +581,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.chip_delay = 0; info->chip.select_chip = nand_davinci_select_chip; - /* options such as NAND_USE_FLASH_BBT */ + /* options such as NAND_BBT_USE_FLASH */ info->chip.bbt_options = pdata->bbt_options; /* options such as 16-bit widths */ info->chip.options = pdata->options; diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index dbb6fbae7d25..ee3014505af2 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1577,7 +1577,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) denali->nand.bbt_md = &bbt_mirror_descr; /* skip the scan for now until we have OOB read and write support */ - denali->nand.bbt_options |= NAND_USE_FLASH_BBT; + denali->nand.bbt_options |= NAND_BBT_USE_FLASH; denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index f70bc73e7948..b657d7f9b05c 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1652,7 +1652,7 @@ static int __init doc_probe(unsigned long physadr) nand->ecc.mode = NAND_ECC_HW_SYNDROME; nand->ecc.size = 512; nand->ecc.bytes = 6; - nand->bbt_options = NAND_USE_FLASH_BBT; + nand->bbt_options = NAND_BBT_USE_FLASH; doc->physadr = physadr; doc->virtadr = virtadr; diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index bff4791d73c3..d4ea5fe013b7 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -792,7 +792,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) /* set up nand options */ chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; - chip->bbt_options = NAND_USE_FLASH_BBT; + chip->bbt_options = NAND_BBT_USE_FLASH; chip->controller = &elbc_fcm_ctrl->controller; chip->priv = priv; diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 0ac64b54bd67..2f2c35a7771e 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -736,7 +736,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) chip->verify_buf = mpc5121_nfc_verify_buf; chip->select_chip = mpc5121_nfc_select_chip; chip->options = NAND_NO_AUTOINCR; - chip->bbt_options = NAND_USE_FLASH_BBT; + chip->bbt_options = NAND_BBT_USE_FLASH; chip->ecc.mode = NAND_ECC_SOFT; /* Support external chip-select logic on ADS5121 board */ diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ed68fde3d1be..ca42c8f335b3 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1179,7 +1179,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; /* update flash based bbt */ - this->bbt_options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_BBT_USE_FLASH; } init_completion(&host->op_completion); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d39dffe71de4..422e7872d6db 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -405,7 +405,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* Do we have a flash based bad block table ? */ - if (chip->bbt_options & NAND_USE_FLASH_BBT) + if (chip->bbt_options & NAND_BBT_USE_FLASH) ret = nand_update_bbt(mtd, ofs); else { nand_get_device(chip, mtd, FL_WRITING); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 66f93e2ac16b..dfea9fd1d61c 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -14,7 +14,7 @@ * * When nand_scan_bbt is called, then it tries to find the bad block table * depending on the options in the BBT descriptor(s). If no flash based BBT - * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory * marked good / bad blocks. This information is used to create a memory BBT. * Once a new bad block is discovered then the "factory" information is updated * on the device. @@ -36,7 +36,7 @@ * The table is marked in the OOB area with an ident pattern and a version * number which indicates which of both tables is more up to date. If the NAND * controller needs the complete OOB area for the ECC information then the - * option NAND_BBT_NO_OOB should be used (along with NAND_USE_FLASH_BBT, of + * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of * course): it moves the ident pattern and the version byte into the data area * and the OOB area will remain untouched. * @@ -1083,14 +1083,14 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) bits = bd->options & NAND_BBT_NRBITS_MSK; BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && - !(this->bbt_options & NAND_USE_FLASH_BBT)); + !(this->bbt_options & NAND_BBT_USE_FLASH)); BUG_ON(!bits); if (bd->options & NAND_BBT_VERSION) pattern_len++; if (bd->options & NAND_BBT_NO_OOB) { - BUG_ON(!(this->bbt_options & NAND_USE_FLASH_BBT)); + BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); BUG_ON(bd->offs); if (bd->options & NAND_BBT_VERSION) @@ -1357,12 +1357,12 @@ int nand_default_bbt(struct mtd_info *mtd) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } - this->bbt_options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_BBT_USE_FLASH; return nand_scan_bbt(mtd, &agand_flashbased); } /* Is a flash based bad block table requested ? */ - if (this->bbt_options & NAND_USE_FLASH_BBT) { + if (this->bbt_options & NAND_BBT_USE_FLASH) { /* Use the default pattern descriptors */ if (!this->bbt_td) { if (this->bbt_options & NAND_BBT_NO_OOB) { diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 1856c42c62c4..34c03be77301 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -2275,7 +2275,7 @@ static int __init ns_init_module(void) case 2: chip->bbt_options |= NAND_BBT_NO_OOB; case 1: - chip->bbt_options |= NAND_USE_FLASH_BBT; + chip->bbt_options |= NAND_BBT_USE_FLASH; case 0: break; default: diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 1c17f091e16b..a97264ececdb 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -156,7 +156,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev) /* Enable the following for a flash based bad block table */ chip->options = NAND_NO_AUTOINCR; - chip->bbt_options = NAND_USE_FLASH_BBT; + chip->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ if (nand_scan(pasemi_nand_mtd, 1)) { diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 370516c3f7c7..ec280798e221 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -881,7 +881,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, * let the kernel fish out the BBT from the NAND, and also skip the * full NAND scan that can take 1/2s or so. Little things... */ if (set->flash_bbt) { - chip->bbt_options |= NAND_USE_FLASH_BBT; + chip->bbt_options |= NAND_BBT_USE_FLASH; chip->options |= NAND_SKIP_BBTSCAN; } } diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 7929514781ea..ff18c0850519 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -104,7 +104,7 @@ struct nand_bbt_descr { * Use a flash based bad block table. By default, OOB identifier is saved in * OOB area. This option is passed to the default bad block table function. */ -#define NAND_USE_FLASH_BBT 0x00040000 +#define NAND_BBT_USE_FLASH 0x00040000 /* Do not store flash based bad block table in OOB area; store it in-band */ #define NAND_BBT_NO_OOB 0x00080000 From b8f80684054ec8a3bcdf35dc9c76ddf629a36482 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 May 2011 16:31:24 -0700 Subject: [PATCH 0149/1596] mtd: nand: move NAND_CREATE_EMPTY_BBT flag The NAND_CREATE_EMPTY_BBT flag was added by commit: 453281a973c10bce941b240d1c654d536623b16b mtd: nand: introduce NAND_CREATE_EMPTY_BBT This flag is not used within the kernel and not explained well, so I took the liberty to edit its comments. Also, this is a BBT-related flag (and closely tied with NAND_BBT_CREATE) so I'm moving it to bbm.h next to NAND_BBT_CREATE, thus requiring that we use the flag in nand_chip.bbt_options, *not* in nand_chip.options. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 2 +- include/linux/mtd/bbm.h | 7 +++++++ include/linux/mtd/nand.h | 2 -- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index dfea9fd1d61c..2e4e25996f03 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -970,7 +970,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc continue; /* Create the table in memory by scanning the chip(s) */ - if (!(this->options & NAND_CREATE_EMPTY_BBT)) + if (!(this->bbt_options & NAND_CREATE_EMPTY_BBT)) create_bbt(mtd, buf, bd, chipsel); td->version[i] = 1; diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index ff18c0850519..3cf4a8adc6af 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -86,6 +86,13 @@ struct nand_bbt_descr { #define NAND_BBT_VERSION 0x00000100 /* Create a bbt if none exists */ #define NAND_BBT_CREATE 0x00000200 +/* + * Create an empty BBT with no vendor information. Vendor's information may be + * unavailable, for example, if the NAND controller has a different data and OOB + * layout or if this information is already purged. Must be used in conjunction + * with NAND_BBT_CREATE. + */ +#define NAND_CREATE_EMPTY_BBT 0x01000000 /* Search good / bad pattern through all pages of a block */ #define NAND_BBT_SCANALLPAGES 0x00000400 /* Scan block empty during good / bad block scan */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 8a086d2cacf4..c1fca4fd35e7 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -228,8 +228,6 @@ typedef enum { #define NAND_OWN_BUFFERS 0x00040000 /* Chip may not exist, so silence any errors in scan */ #define NAND_SCAN_SILENT_NODEV 0x00080000 -/* Create an empty BBT with no vendor information if the BBT is available */ -#define NAND_CREATE_EMPTY_BBT 0x01000000 /* Options set by nand scan */ /* Nand scan has allocated controller struct */ From 53d5d8885089b8abeb487392311ed18f897deb93 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 May 2011 16:31:25 -0700 Subject: [PATCH 0150/1596] mtd: nand: rename CREATE_EMPTY bbt flag with proper prefix According to our new prefix rules, we should rename NAND_CREATE_EMPTY_BBT with a NAND_BBT prefix, i.e., NAND_BBT_CREATE_EMPTY. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 2 +- include/linux/mtd/bbm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 2e4e25996f03..9af703def4aa 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -970,7 +970,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc continue; /* Create the table in memory by scanning the chip(s) */ - if (!(this->bbt_options & NAND_CREATE_EMPTY_BBT)) + if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) create_bbt(mtd, buf, bd, chipsel); td->version[i] = 1; diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 3cf4a8adc6af..0fa030ae29d6 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -92,7 +92,7 @@ struct nand_bbt_descr { * layout or if this information is already purged. Must be used in conjunction * with NAND_BBT_CREATE. */ -#define NAND_CREATE_EMPTY_BBT 0x01000000 +#define NAND_BBT_CREATE_EMPTY 0x01000000 /* Search good / bad pattern through all pages of a block */ #define NAND_BBT_SCANALLPAGES 0x00000400 /* Scan block empty during good / bad block scan */ From b4dc53e16ff00c0edba3d3219e216475e68951b3 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 May 2011 16:31:26 -0700 Subject: [PATCH 0151/1596] mtd: nand: renumber the reorganized flags in nand.h / bbm.h After several steps of rearrangement and consolidation, it is probably worth re-sequencing the numbers on some of our affected flags in nand.h and bbm.h. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/linux/mtd/bbm.h | 23 ++++++++++++----------- include/linux/mtd/nand.h | 6 +++--- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 0fa030ae29d6..57d6a8d4aa17 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -92,28 +92,29 @@ struct nand_bbt_descr { * layout or if this information is already purged. Must be used in conjunction * with NAND_BBT_CREATE. */ -#define NAND_BBT_CREATE_EMPTY 0x01000000 +#define NAND_BBT_CREATE_EMPTY 0x00000400 /* Search good / bad pattern through all pages of a block */ -#define NAND_BBT_SCANALLPAGES 0x00000400 +#define NAND_BBT_SCANALLPAGES 0x00000800 /* Scan block empty during good / bad block scan */ -#define NAND_BBT_SCANEMPTY 0x00000800 +#define NAND_BBT_SCANEMPTY 0x00001000 /* Write bbt if neccecary */ -#define NAND_BBT_WRITE 0x00001000 +#define NAND_BBT_WRITE 0x00002000 /* Read and write back block contents when writing bbt */ -#define NAND_BBT_SAVECONTENT 0x00002000 +#define NAND_BBT_SAVECONTENT 0x00004000 /* Search good / bad pattern on the first and the second page */ -#define NAND_BBT_SCAN2NDPAGE 0x00004000 +#define NAND_BBT_SCAN2NDPAGE 0x00008000 /* Search good / bad pattern on the last page of the eraseblock */ -#define NAND_BBT_SCANLASTPAGE 0x00008000 -/* The nand_bbt_descr was created dynamicaly and must be freed */ -#define NAND_BBT_DYNAMICSTRUCT 0x00200000 +#define NAND_BBT_SCANLASTPAGE 0x00010000 /* * Use a flash based bad block table. By default, OOB identifier is saved in * OOB area. This option is passed to the default bad block table function. */ -#define NAND_BBT_USE_FLASH 0x00040000 +#define NAND_BBT_USE_FLASH 0x00020000 /* Do not store flash based bad block table in OOB area; store it in-band */ -#define NAND_BBT_NO_OOB 0x00080000 +#define NAND_BBT_NO_OOB 0x00040000 + +/* The nand_bbt_descr was created dynamicaly and must be freed */ +#define NAND_BBT_DYNAMICSTRUCT 0x80000000 /* The maximum number of blocks to scan for a bbt */ #define NAND_BBT_SCAN_MAXBLOCKS 4 diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c1fca4fd35e7..4a43ffc535c9 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -220,14 +220,14 @@ typedef enum { /* Non chip related options */ /* This option skips the bbt scan during initialization. */ -#define NAND_SKIP_BBTSCAN 0x00020000 +#define NAND_SKIP_BBTSCAN 0x00010000 /* * This option is defined if the board driver allocates its own buffers * (e.g. because it needs them DMA-coherent). */ -#define NAND_OWN_BUFFERS 0x00040000 +#define NAND_OWN_BUFFERS 0x00020000 /* Chip may not exist, so silence any errors in scan */ -#define NAND_SCAN_SILENT_NODEV 0x00080000 +#define NAND_SCAN_SILENT_NODEV 0x00040000 /* Options set by nand scan */ /* Nand scan has allocated controller struct */ From 9eeff8243677b8bbfc17e8e606e965bb591a759d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 May 2011 16:31:27 -0700 Subject: [PATCH 0152/1596] mtd: nand: improve comment on NAND_BBT_DYNAMIC_STRUCT In an attempt to improve the documentation of the BBT code, I am expanding the comments I left in commit: 58373ff0afff4cc8ac40608872995f4d87eb72ec mtd: nand: more BB Detection refactoring and dynamic scan options Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/linux/mtd/bbm.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 57d6a8d4aa17..c4eec228eef9 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -113,7 +113,11 @@ struct nand_bbt_descr { /* Do not store flash based bad block table in OOB area; store it in-band */ #define NAND_BBT_NO_OOB 0x00040000 -/* The nand_bbt_descr was created dynamicaly and must be freed */ +/* + * Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr + * was allocated dynamicaly and must be freed in nand_release(). Has no meaning + * in nand_chip.bbt_options. + */ #define NAND_BBT_DYNAMICSTRUCT 0x80000000 /* The maximum number of blocks to scan for a bbt */ From 1754aab9bb869c173aa03b57587256827250e488 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 17:49:22 +0400 Subject: [PATCH 0153/1596] mtd: ATMEL, AVR32: inline nand partition table access Currently atmel_nand driver used by AT91 and AVR32 calls a special callback which return nand partition table and number of partitions. However in all boards this callback returns just static data. So drop this callback and make atmel_nand use partition table provided statically via platform_data. Nicolas Ferre: I am in favor for a mainline inclusion through linux-mtd tree. Hans-Christian Egtvedt: I'm fine by sending the changes for AVR32 through linux-mtd Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Hans-Christian Egtvedt Acked-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Artem Bityutskiy --- arch/arm/mach-at91/board-afeb-9260v1.c | 9 ++------- arch/arm/mach-at91/board-cam60.c | 9 ++------- arch/arm/mach-at91/board-cap9adk.c | 9 ++------- arch/arm/mach-at91/board-kb9202.c | 9 ++------- arch/arm/mach-at91/board-neocore926.c | 9 ++------- arch/arm/mach-at91/board-qil-a9260.c | 9 ++------- arch/arm/mach-at91/board-rm9200dk.c | 9 ++------- arch/arm/mach-at91/board-sam9-l9260.c | 9 ++------- arch/arm/mach-at91/board-sam9260ek.c | 9 ++------- arch/arm/mach-at91/board-sam9261ek.c | 9 ++------- arch/arm/mach-at91/board-sam9263ek.c | 9 ++------- arch/arm/mach-at91/board-sam9g20ek.c | 9 ++------- arch/arm/mach-at91/board-sam9m10g45ek.c | 9 ++------- arch/arm/mach-at91/board-sam9rlek.c | 9 ++------- arch/arm/mach-at91/board-snapper9260.c | 10 ++-------- arch/arm/mach-at91/board-usb-a9260.c | 9 ++------- arch/arm/mach-at91/board-usb-a9263.c | 9 ++------- arch/arm/mach-at91/board-yl-9200.c | 9 ++------- arch/arm/mach-at91/include/mach/board.h | 3 ++- arch/avr32/boards/atngw100/setup.c | 8 ++------ arch/avr32/boards/atstk1000/atstk1002.c | 9 ++------- arch/avr32/mach-at32ap/include/mach/board.h | 3 ++- drivers/mtd/nand/atmel_nand.c | 7 ++++--- 23 files changed, 48 insertions(+), 145 deletions(-) diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c index b0c796d42e49..a053e915c279 100644 --- a/arch/arm/mach-at91/board-afeb-9260v1.c +++ b/arch/arm/mach-at91/board-afeb-9260v1.c @@ -130,19 +130,14 @@ static struct mtd_partition __initdata afeb9260_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(afeb9260_nand_partition); - return afeb9260_nand_partition; -} - static struct atmel_nand_data __initdata afeb9260_nand_data = { .ale = 21, .cle = 22, .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, - .partition_info = nand_partitions, .bus_width_16 = 0, + .parts = afeb9260_nand_partition, + .num_parts = ARRAY_SIZE(afeb9260_nand_partition), }; diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c index d1abd5898e85..46f8bab9c943 100644 --- a/arch/arm/mach-at91/board-cam60.c +++ b/arch/arm/mach-at91/board-cam60.c @@ -132,19 +132,14 @@ static struct mtd_partition __initdata cam60_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(cam60_nand_partition); - return cam60_nand_partition; -} - static struct atmel_nand_data __initdata cam60_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not there .rdy_pin = AT91_PIN_PA9, .enable_pin = AT91_PIN_PA7, - .partition_info = nand_partitions, + .parts = cam60_nand_partition, + .num_parts = ARRAY_SIZE(cam60_nand_partition), }; static struct sam9_smc_config __initdata cam60_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c index 679b0b743e92..858927e2aff5 100644 --- a/arch/arm/mach-at91/board-cap9adk.c +++ b/arch/arm/mach-at91/board-cap9adk.c @@ -169,19 +169,14 @@ static struct mtd_partition __initdata cap9adk_nand_partitions[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(cap9adk_nand_partitions); - return cap9adk_nand_partitions; -} - static struct atmel_nand_data __initdata cap9adk_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not connected // .rdy_pin = ... not connected .enable_pin = AT91_PIN_PD15, - .partition_info = nand_partitions, + .parts = cap9adk_nand_partitions, + .num_parts = ARRAY_SIZE(cap9adk_nand_partitions), }; static struct sam9_smc_config __initdata cap9adk_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c index 9dc8d496ead1..94372441c1aa 100644 --- a/arch/arm/mach-at91/board-kb9202.c +++ b/arch/arm/mach-at91/board-kb9202.c @@ -97,19 +97,14 @@ static struct mtd_partition __initdata kb9202_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(kb9202_nand_partition); - return kb9202_nand_partition; -} - static struct atmel_nand_data __initdata kb9202_nand_data = { .ale = 22, .cle = 21, // .det_pin = ... not there .rdy_pin = AT91_PIN_PC29, .enable_pin = AT91_PIN_PC28, - .partition_info = nand_partitions, + .parts = kb9202_nand_partition, + .num_parts = ARRAY_SIZE(kb9202_nand_partition), }; static void __init kb9202_board_init(void) diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c index 9bc6ab32e0ac..60f0cee074dc 100644 --- a/arch/arm/mach-at91/board-neocore926.c +++ b/arch/arm/mach-at91/board-neocore926.c @@ -182,19 +182,14 @@ static struct mtd_partition __initdata neocore926_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(neocore926_nand_partition); - return neocore926_nand_partition; -} - static struct atmel_nand_data __initdata neocore926_nand_data = { .ale = 21, .cle = 22, .rdy_pin = AT91_PIN_PB19, .rdy_pin_active_low = 1, .enable_pin = AT91_PIN_PD15, - .partition_info = nand_partitions, + .parts = neocore926_nand_partition, + .num_parts = ARRAY_SIZE(neocore926_nand_partition), }; static struct sam9_smc_config __initdata neocore926_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c index 81f911033681..78d71e45d744 100644 --- a/arch/arm/mach-at91/board-qil-a9260.c +++ b/arch/arm/mach-at91/board-qil-a9260.c @@ -130,19 +130,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c index 6f08faadb474..b5f2faf479f6 100644 --- a/arch/arm/mach-at91/board-rm9200dk.c +++ b/arch/arm/mach-at91/board-rm9200dk.c @@ -138,19 +138,14 @@ static struct mtd_partition __initdata dk_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(dk_nand_partition); - return dk_nand_partition; -} - static struct atmel_nand_data __initdata dk_nand_data = { .ale = 22, .cle = 21, .det_pin = AT91_PIN_PB1, .rdy_pin = AT91_PIN_PC2, // .enable_pin = ... not there - .partition_info = nand_partitions, + .parts = dk_nand_partition, + .num_parts = ARRAY_SIZE(dk_nand_partition), }; #define DK_FLASH_BASE AT91_CHIPSELECT_0 diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c index 4d3a02f1289e..4128f6d8e902 100644 --- a/arch/arm/mach-at91/board-sam9-l9260.c +++ b/arch/arm/mach-at91/board-sam9-l9260.c @@ -131,19 +131,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c index 8a50c3e67186..2cf7ce25a33e 100644 --- a/arch/arm/mach-at91/board-sam9260ek.c +++ b/arch/arm/mach-at91/board-sam9260ek.c @@ -173,19 +173,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 5096a0ec50c1..b7f35d0e9e54 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -179,19 +179,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - static struct atmel_nand_data __initdata ek_nand_data = { .ale = 22, .cle = 21, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PC15, .enable_pin = AT91_PIN_PC14, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index ea8f185d3b9d..5d2bd12b41a8 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -180,19 +180,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PA22, .enable_pin = AT91_PIN_PD15, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index 817f59d7251b..003122772e63 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c @@ -157,19 +157,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - /* det_pin is not connected */ static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c index ad234ccbf57e..00d041ca8dbe 100644 --- a/arch/arm/mach-at91/board-sam9m10g45ek.c +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c @@ -137,19 +137,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - /* det_pin is not connected */ static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, .rdy_pin = AT91_PIN_PC8, .enable_pin = AT91_PIN_PC14, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c index 4f14b54b93a8..6178b4e7f1aa 100644 --- a/arch/arm/mach-at91/board-sam9rlek.c +++ b/arch/arm/mach-at91/board-sam9rlek.c @@ -88,19 +88,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PD17, .enable_pin = AT91_PIN_PB6, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c index c73d25e5faea..0df01c6e2d0c 100644 --- a/arch/arm/mach-at91/board-snapper9260.c +++ b/arch/arm/mach-at91/board-snapper9260.c @@ -97,18 +97,12 @@ static struct mtd_partition __initdata snapper9260_nand_partitions[] = { }, }; -static struct mtd_partition * __init -snapper9260_nand_partition_info(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(snapper9260_nand_partitions); - return snapper9260_nand_partitions; -} - static struct atmel_nand_data __initdata snapper9260_nand_data = { .ale = 21, .cle = 22, .rdy_pin = AT91_PIN_PC13, - .partition_info = snapper9260_nand_partition_info, + .parts = snapper9260_nand_partitions, + .num_parts = ARRAY_SIZE(snapper9260_nand_partitions), .bus_width_16 = 0, }; diff --git a/arch/arm/mach-at91/board-usb-a9260.c b/arch/arm/mach-at91/board-usb-a9260.c index 8c4c1a02c4be..73e572302a4a 100644 --- a/arch/arm/mach-at91/board-usb-a9260.c +++ b/arch/arm/mach-at91/board-usb-a9260.c @@ -104,19 +104,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { } }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-usb-a9263.c b/arch/arm/mach-at91/board-usb-a9263.c index 25e793782a4e..909fd9743950 100644 --- a/arch/arm/mach-at91/board-usb-a9263.c +++ b/arch/arm/mach-at91/board-usb-a9263.c @@ -117,19 +117,14 @@ static struct mtd_partition __initdata ek_nand_partition[] = { } }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(ek_nand_partition); - return ek_nand_partition; -} - static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21, .cle = 22, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PA22, .enable_pin = AT91_PIN_PD15, - .partition_info = nand_partitions, + .parts = ek_nand_partition, + .num_parts = ARRAY_SIZE(ek_nand_partition), }; static struct sam9_smc_config __initdata ek_nand_smc_config = { diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c index 95edcbd2aec6..7511fb83865a 100644 --- a/arch/arm/mach-at91/board-yl-9200.c +++ b/arch/arm/mach-at91/board-yl-9200.c @@ -172,19 +172,14 @@ static struct mtd_partition __initdata yl9200_nand_partition[] = { } }; -static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(yl9200_nand_partition); - return yl9200_nand_partition; -} - static struct atmel_nand_data __initdata yl9200_nand_data = { .ale = 6, .cle = 7, // .det_pin = ... not connected .rdy_pin = AT91_PIN_PC14, /* R/!B (Sheet10) */ .enable_pin = AT91_PIN_PC15, /* !CE (Sheet10) */ - .partition_info = nand_partitions, + .parts = yl9200_nand_partition, + .num_parts = ARRAY_SIZE(yl9200_nand_partition), }; /* diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index ed544a0d5a1d..664353198bc0 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -112,7 +112,8 @@ struct atmel_nand_data { u8 ale; /* address line number connected to ALE */ u8 cle; /* address line number connected to CLE */ u8 bus_width_16; /* buswidth is 16 bit */ - struct mtd_partition* (*partition_info)(int, int*); + struct mtd_partition *parts; + unsigned int num_parts; }; extern void __init at91_add_device_nand(struct atmel_nand_data *data); diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index fafed4c38fd2..1f17bde52cd4 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -90,11 +90,6 @@ static struct mtd_partition nand_partitions[] = { }, }; -static struct mtd_partition *nand_part_info(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(nand_partitions); - return nand_partitions; -} static struct atmel_nand_data atngw100mkii_nand_data __initdata = { .cle = 21, @@ -102,7 +97,8 @@ static struct atmel_nand_data atngw100mkii_nand_data __initdata = { .rdy_pin = GPIO_PIN_PB(28), .enable_pin = GPIO_PIN_PE(23), .bus_width_16 = true, - .partition_info = nand_part_info, + .parts = nand_partitions, + .num_parts = ARRAY_SIZE(nand_partitions), }; #endif diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c index 6ce30fb2ec94..4643ff5107c9 100644 --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -90,18 +90,13 @@ static struct mtd_partition nand_partitions[] = { }, }; -static struct mtd_partition *nand_part_info(int size, int *num_partitions) -{ - *num_partitions = ARRAY_SIZE(nand_partitions); - return nand_partitions; -} - static struct atmel_nand_data atstk1006_nand_data __initdata = { .cle = 21, .ale = 22, .rdy_pin = GPIO_PIN_PB(30), .enable_pin = GPIO_PIN_PB(29), - .partition_info = nand_part_info, + .parts = nand_partitions, + .num_parts = ARRAY_SIZE(num_partitions), }; #endif diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h index 679458d9a622..5d7ffca7d69f 100644 --- a/arch/avr32/mach-at32ap/include/mach/board.h +++ b/arch/avr32/mach-at32ap/include/mach/board.h @@ -128,7 +128,8 @@ struct atmel_nand_data { u8 ale; /* address line number connected to ALE */ u8 cle; /* address line number connected to CLE */ u8 bus_width_16; /* buswidth is 16 bit */ - struct mtd_partition *(*partition_info)(int size, int *num_partitions); + struct mtd_partition *parts; + unsigned int num_parts; }; struct platform_device * at32_add_device_nand(unsigned int id, struct atmel_nand_data *data); diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 79a7ef276616..01fb5f0adcf0 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -660,9 +660,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev) num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0); #endif - if (num_partitions <= 0 && host->board->partition_info) - partitions = host->board->partition_info(mtd->size, - &num_partitions); + if (num_partitions <= 0 && host->board->parts) { + partitions = host->board->parts; + num_partitions = host->board->num_parts; + } if ((!partitions) || (num_partitions == 0)) { printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n"); From d3f2ed520b51f06d4f3c8c96bd4ba6e7e57643a3 Mon Sep 17 00:00:00 2001 From: Jiri Pinkava Date: Wed, 1 Jun 2011 15:56:40 +0200 Subject: [PATCH 0154/1596] mtd: nand: remove meaningless delay from nand_unlock This delay is meaningless. If delay is needed it is device specific and must be reimplemented by specific driver, otherwise no delay is needed. Signed-off-by: Jiri Pinkava Acked-by: Vimal Singh Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 422e7872d6db..e57ea8322812 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -915,7 +915,6 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, /* Call wait ready function */ status = chip->waitfunc(mtd, chip); - udelay(1000); /* See if device thinks it succeeded */ if (status & 0x01) { DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", @@ -1024,7 +1023,6 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Call wait ready function */ status = chip->waitfunc(mtd, chip); - udelay(1000); /* See if device thinks it succeeded */ if (status & 0x01) { DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", From 06947494bea31e536eba1d5c7d95791a9d2b5a99 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 15:54:08 +0400 Subject: [PATCH 0155/1596] mtd: drop ceiva map driver It's a Ceiva/Polaroid PhotoMax Digital Picture Frame. Support for it was commited before 2.6.12-rc2, current git contains no functional changes since it's start. Driver containing MTD support for that board was broken for some time already. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/Kconfig | 8 - drivers/mtd/maps/Makefile | 1 - drivers/mtd/maps/ceiva.c | 341 -------------------------------------- 3 files changed, 350 deletions(-) delete mode 100644 drivers/mtd/maps/ceiva.c diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index c0c328c5b133..11cc2307c2ca 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -412,14 +412,6 @@ config MTD_IMPA7 This enables access to the NOR Flash on the impA7 board of implementa GmbH. If you have such a board, say 'Y' here. -config MTD_CEIVA - tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" - depends on MTD_JEDECPROBE && ARCH_CEIVA - help - This enables access to the flash chips on the Ceiva/Polaroid - PhotoMax Digital Picture Frame. - If you have such a device, say 'Y'. - config MTD_H720X tristate "Hynix evaluation board mappings" depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index cb48b11affff..d6379fea42b8 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o obj-$(CONFIG_MTD_MBX860) += mbx860.o -obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c deleted file mode 100644 index 06f9c9815720..000000000000 --- a/drivers/mtd/maps/ceiva.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Ceiva flash memory driver. - * Copyright (C) 2002 Rob Scott - * - * Note: this driver supports jedec compatible devices. Modification - * for CFI compatible devices should be straight forward: change - * jedec_probe to cfi_probe. - * - * Based on: sa1100-flash.c, which has the following copyright: - * Flash memory access on SA11x0 based devices - * - * (C) 2000 Nicolas Pitre - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * This isn't complete yet, so... - */ -#define CONFIG_MTD_CEIVA_STATICMAP - -#ifdef CONFIG_MTD_CEIVA_STATICMAP -/* - * See include/linux/mtd/partitions.h for definition of the mtd_partition - * structure. - * - * Please note: - * 1. The flash size given should be the largest flash size that can - * be accommodated. - * - * 2. The bus width must defined in clps_setup_flash. - * - * The MTD layer will detect flash chip aliasing and reduce the size of - * the map accordingly. - * - */ - -#ifdef CONFIG_ARCH_CEIVA -/* Flash / Partition sizing */ -/* For the 28F8003, we use the block mapping to calcuate the sizes */ -#define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128)) -#define BOOT_PARTITION_SIZE_KiB (16) -#define PARAMS_PARTITION_SIZE_KiB (8) -#define KERNEL_PARTITION_SIZE_KiB (4*128) -/* Use both remaining portion of first flash, and all of second flash */ -#define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128) - -static struct mtd_partition ceiva_partitions[] = { - { - .name = "Ceiva BOOT partition", - .size = BOOT_PARTITION_SIZE_KiB*1024, - .offset = 0, - - },{ - .name = "Ceiva parameters partition", - .size = PARAMS_PARTITION_SIZE_KiB*1024, - .offset = (16 + 8) * 1024, - },{ - .name = "Ceiva kernel partition", - .size = (KERNEL_PARTITION_SIZE_KiB)*1024, - .offset = 0x20000, - - },{ - .name = "Ceiva root filesystem partition", - .offset = MTDPART_OFS_APPEND, - .size = (ROOT_PARTITION_SIZE_KiB)*1024, - } -}; -#endif - -static int __init clps_static_partitions(struct mtd_partition **parts) -{ - int nb_parts = 0; - -#ifdef CONFIG_ARCH_CEIVA - if (machine_is_ceiva()) { - *parts = ceiva_partitions; - nb_parts = ARRAY_SIZE(ceiva_partitions); - } -#endif - return nb_parts; -} -#endif - -struct clps_info { - unsigned long base; - unsigned long size; - int width; - void *vbase; - struct map_info *map; - struct mtd_info *mtd; - struct resource *res; -}; - -#define NR_SUBMTD 4 - -static struct clps_info info[NR_SUBMTD]; - -static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd) -{ - struct mtd_info *subdev[nr]; - struct map_info *maps; - int i, found = 0, ret = 0; - - /* - * Allocate the map_info structs in one go. - */ - maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL); - if (!maps) - return -ENOMEM; - /* - * Claim and then map the memory regions. - */ - for (i = 0; i < nr; i++) { - if (clps[i].base == (unsigned long)-1) - break; - - clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash"); - if (!clps[i].res) { - ret = -EBUSY; - break; - } - - clps[i].map = maps + i; - - clps[i].map->name = "clps flash"; - clps[i].map->phys = clps[i].base; - - clps[i].vbase = ioremap(clps[i].base, clps[i].size); - if (!clps[i].vbase) { - ret = -ENOMEM; - break; - } - - clps[i].map->virt = (void __iomem *)clps[i].vbase; - clps[i].map->bankwidth = clps[i].width; - clps[i].map->size = clps[i].size; - - simple_map_init(&clps[i].map); - - clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); - if (clps[i].mtd == NULL) { - ret = -ENXIO; - break; - } - clps[i].mtd->owner = THIS_MODULE; - subdev[i] = clps[i].mtd; - - printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " - "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20, - clps[i].width * 8); - found += 1; - } - - /* - * ENXIO is special. It means we didn't find a chip when - * we probed. We need to tear down the mapping, free the - * resource and mark it as such. - */ - if (ret == -ENXIO) { - iounmap(clps[i].vbase); - clps[i].vbase = NULL; - release_resource(clps[i].res); - clps[i].res = NULL; - } - - /* - * If we found one device, don't bother with concat support. - * If we found multiple devices, use concat if we have it - * available, otherwise fail. - */ - if (ret == 0 || ret == -ENXIO) { - if (found == 1) { - *rmtd = subdev[0]; - ret = 0; - } else if (found > 1) { - /* - * We detected multiple devices. Concatenate - * them together. - */ - *rmtd = mtd_concat_create(subdev, found, - "clps flash"); - if (*rmtd == NULL) - ret = -ENXIO; - } - } - - /* - * If we failed, clean up. - */ - if (ret) { - do { - if (clps[i].mtd) - map_destroy(clps[i].mtd); - if (clps[i].vbase) - iounmap(clps[i].vbase); - if (clps[i].res) - release_resource(clps[i].res); - } while (i--); - - kfree(maps); - } - - return ret; -} - -static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd) -{ - int i; - - mtd_device_unregister(mtd); - - if (mtd != clps[0].mtd) - mtd_concat_destroy(mtd); - - for (i = NR_SUBMTD; i >= 0; i--) { - if (clps[i].mtd) - map_destroy(clps[i].mtd); - if (clps[i].vbase) - iounmap(clps[i].vbase); - if (clps[i].res) - release_resource(clps[i].res); - } - kfree(clps[0].map); -} - -/* - * We define the memory space, size, and width for the flash memory - * space here. - */ - -static int __init clps_setup_flash(void) -{ - int nr = 0; - -#ifdef CONFIG_ARCH_CEIVA - if (machine_is_ceiva()) { - info[0].base = CS0_PHYS_BASE; - info[0].size = SZ_32M; - info[0].width = CEIVA_FLASH_WIDTH; - info[1].base = CS1_PHYS_BASE; - info[1].size = SZ_32M; - info[1].width = CEIVA_FLASH_WIDTH; - nr = 2; - } -#endif - return nr; -} - -static struct mtd_partition *parsed_parts; -static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; - -static void __init clps_locate_partitions(struct mtd_info *mtd) -{ - const char *part_type = NULL; - int nr_parts = 0; - do { - /* - * Partition selection stuff. - */ - nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); - if (nr_parts > 0) { - part_type = "command line"; - break; - } -#ifdef CONFIG_MTD_CEIVA_STATICMAP - nr_parts = clps_static_partitions(&parsed_parts); - if (nr_parts > 0) { - part_type = "static"; - break; - } - printk("found: %d partitions\n", nr_parts); -#endif - } while (0); - - if (nr_parts == 0) { - printk(KERN_NOTICE "clps flash: no partition info " - "available, registering whole flash\n"); - mtd_device_register(mtd, NULL, 0); - } else { - printk(KERN_NOTICE "clps flash: using %s partition " - "definition\n", part_type); - mtd_device_register(mtd, parsed_parts, nr_parts); - } - - /* Always succeeds. */ -} - -static void __exit clps_destroy_partitions(void) -{ - kfree(parsed_parts); -} - -static struct mtd_info *mymtd; - -static int __init clps_mtd_init(void) -{ - int ret; - int nr; - - nr = clps_setup_flash(); - if (nr < 0) - return nr; - - ret = clps_setup_mtd(info, nr, &mymtd); - if (ret) - return ret; - - clps_locate_partitions(mymtd); - - return 0; -} - -static void __exit clps_mtd_cleanup(void) -{ - clps_destroy_mtd(info, mymtd); - clps_destroy_partitions(); -} - -module_init(clps_mtd_init); -module_exit(clps_mtd_cleanup); - -MODULE_AUTHOR("Rob Scott"); -MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver"); -MODULE_LICENSE("GPL"); From 13e0fe49f676607688da7475c33540ec5dac53b5 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:51:14 +0400 Subject: [PATCH 0156/1596] mtd: drop physmap_configure physmap_configure() and physmap_set_partitions() have no users in kernel. Out of kernel users should have been converted to regular platform device long ago. Drop support for this obsolete API. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/Kconfig | 6 ------ drivers/mtd/maps/physmap.c | 15 --------------- include/linux/mtd/physmap.h | 17 ----------------- 3 files changed, 38 deletions(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 11cc2307c2ca..46eca3b3bcb0 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -41,8 +41,6 @@ config MTD_PHYSMAP_START are mapped on your particular target board. Refer to the memory map which should hopefully be in the documentation for your board. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_LEN hex "Physical length of flash mapping" @@ -55,8 +53,6 @@ config MTD_PHYSMAP_LEN than the total amount of flash present. Refer to the memory map which should hopefully be in the documentation for your board. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_BANKWIDTH int "Bank width in octets" @@ -67,8 +63,6 @@ config MTD_PHYSMAP_BANKWIDTH in octets. For example, if you have a data bus width of 32 bits, you would set the bus width octet value to 4. This is used internally by the CFI drivers. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_OF tristate "Flash device in physical memory map based on OF description" diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index f64cee4a3bfb..2174d103297e 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -245,21 +245,6 @@ static struct platform_device physmap_flash = { .num_resources = 1, .resource = &physmap_flash_resource, }; - -void physmap_configure(unsigned long addr, unsigned long size, - int bankwidth, void (*set_vpp)(struct map_info *, int)) -{ - physmap_flash_resource.start = addr; - physmap_flash_resource.end = addr + size - 1; - physmap_flash_data.width = bankwidth; - physmap_flash_data.set_vpp = set_vpp; -} - -void physmap_set_partitions(struct mtd_partition *parts, int num_parts) -{ - physmap_flash_data.nr_parts = num_parts; - physmap_flash_data.parts = parts; -} #endif static int __init physmap_init(void) diff --git a/include/linux/mtd/physmap.h b/include/linux/mtd/physmap.h index e5f21d293c70..04e018160e2b 100644 --- a/include/linux/mtd/physmap.h +++ b/include/linux/mtd/physmap.h @@ -32,21 +32,4 @@ struct physmap_flash_data { struct mtd_partition *parts; }; -/* - * Board needs to specify the exact mapping during their setup time. - */ -void physmap_configure(unsigned long addr, unsigned long size, - int bankwidth, void (*set_vpp)(struct map_info *, int) ); - -/* - * Machines that wish to do flash partition may want to call this function in - * their setup routine. - * - * physmap_set_partitions(mypartitions, num_parts); - * - * Note that one can always override this hard-coded partition with - * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS). - */ -void physmap_set_partitions(struct mtd_partition *parts, int num_parts); - #endif /* __LINUX_MTD_PHYSMAP__ */ From 2e7485f49984ad9cea2d039acfd0554217710cce Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:51:15 +0400 Subject: [PATCH 0157/1596] mtd: cafe_nand: drop reference to CONFIG_MTD_CMDLINE_PARTS There is no need to guard mtd->name with CONFIG_MTD_CMDLINE_PARTS as name can be used by other parts. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/cafe_nand.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index d0eed498ed2b..88ac4b598abc 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -803,9 +803,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, /* We register the whole device first, separate from the partitions */ mtd_device_register(mtd, NULL, 0); -#ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "cafe_nand"; -#endif nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); if (nr_parts > 0) { cafe->parts = parts; From 5c4eefbd5bb82a525ce5340cc8a91ab6dffeb490 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:51:16 +0400 Subject: [PATCH 0158/1596] mtd: mtdpart: default to cmdlinepart, NULL partitions probing Lots of MTD devices default to cmdlinepart, NULL as partition parsing order. Make it a default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdpart.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 630be3e7da04..3477e16be1c8 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -712,12 +712,17 @@ int deregister_mtd_parser(struct mtd_part_parser *p) } EXPORT_SYMBOL_GPL(deregister_mtd_parser); +static const char *default_mtd_part_types[] = {"cmdlinepart", NULL}; + int parse_mtd_partitions(struct mtd_info *master, const char **types, struct mtd_partition **pparts, unsigned long origin) { struct mtd_part_parser *parser; int ret = 0; + if (!types) + types = default_mtd_part_types; + for ( ; ret <= 0 && *types; types++) { parser = get_partition_parser(*types); if (!parser && !request_module("%s", *types)) From 4d1220f6fa03f60a3d3995683911d29ae9c317f7 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:51:17 +0400 Subject: [PATCH 0159/1596] mtd: m25p80 don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/m25p80.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 35180e475c4c..70d5fcacc3fd 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -968,13 +968,7 @@ static int __devinit m25p_probe(struct spi_device *spi) /* partitions should match sector boundaries; and it may be good to * use readonly partitions for writeprotected sectors (BP2..BP0). */ - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] - = { "cmdlinepart", NULL, }; - - nr_parts = parse_mtd_partitions(&flash->mtd, - part_probes, &parts, 0); - } + nr_parts = parse_mtd_partitions(&flash->mtd, NULL, &parts, 0); if (nr_parts <= 0 && data && data->parts) { parts = data->parts; From ae2dbad7e9ee2889e57b5ebac5a60d2d4f03439e Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:51:18 +0400 Subject: [PATCH 0160/1596] mtd: drop mtd_has_cmdlinepart() This function is unused now. Drop it. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- include/linux/mtd/partitions.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 3a6f0372fc96..08c9c7b8b8e2 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -83,12 +83,6 @@ static inline int of_mtd_parse_partitions(struct device *dev, } #endif -#ifdef CONFIG_MTD_CMDLINE_PARTS -static inline int mtd_has_cmdlinepart(void) { return 1; } -#else -static inline int mtd_has_cmdlinepart(void) { return 0; } -#endif - int mtd_is_partition(struct mtd_info *mtd); int mtd_add_partition(struct mtd_info *master, char *name, long long offset, long long length); From 5507766b639e53b9230484588eba8b4e18d0563b Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 2 Jun 2011 11:38:26 -0700 Subject: [PATCH 0161/1596] mtd: nand: remove unnecessary TODO I believe this TODO was unnecessary back when it was introduced: commit d1e1f4e42b5df063712ca2926e50c07b95c96b96 mtd: nand: add support for reading ONFI parameters... Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e57ea8322812..1380bf6c44c7 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3135,7 +3135,6 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - /* TODO onfi flash name */ printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, From b07948251f563379885ac92412fb3885c976e423 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 3 Jun 2011 09:12:15 +0800 Subject: [PATCH 0162/1596] mtd: denali: remove calling mtd_device_unregister() after nand_release() The implementation of nand_release() already call mtd_device_unregister(), no need to call it again. Signed-off-by: Axel Lin Acked-by: Jamie Iles Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/denali.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index ee3014505af2..eebdfb5148e6 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1677,7 +1677,6 @@ static void denali_pci_remove(struct pci_dev *dev) struct denali_nand_info *denali = pci_get_drvdata(dev); nand_release(&denali->mtd); - mtd_device_unregister(&denali->mtd); denali_irq_cleanup(dev->irq, denali); From 43c6871cae298e28700ca1ea76dc94b5f69446bc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 3 Jun 2011 09:51:53 +0800 Subject: [PATCH 0163/1596] mtd: nuc900_nand: add missing nand_release in nuc900_nand_remove Signed-off-by: Axel Lin Acked-by: Wan ZongShun Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nuc900_nand.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 9c30a0b03171..fa8faedfad6e 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -339,6 +339,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev) struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); struct resource *res; + nand_release(&nuc900_nand->mtd); iounmap(nuc900_nand->reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); From d80932b2dc497faa27e415c12f56f6ae1d087204 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 3 Jun 2011 09:53:26 +0800 Subject: [PATCH 0164/1596] mtd: nomadik_nand: add missing nand_release in nomadik_nand_remove Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nomadik_nand.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c index b6a5c86ab31e..b463ecfb4c1a 100644 --- a/drivers/mtd/nand/nomadik_nand.c +++ b/drivers/mtd/nand/nomadik_nand.c @@ -187,6 +187,7 @@ static int nomadik_nand_remove(struct platform_device *pdev) pdata->exit(); if (host) { + nand_release(&host->mtd); iounmap(host->cmd_va); iounmap(host->data_va); iounmap(host->addr_va); From 1a3591920e5100ba112a19e10a09ce7a5da1ab23 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 3 Jun 2011 13:14:10 +0800 Subject: [PATCH 0165/1596] mtd: pxa3xx_nand: fix a memory leak In pxa3xx_nand_remove, we should call nand_release instead of mtd_device_unregister to properly free bad block table memory and bad block descriptor memory. Signed-off-by: Axel Lin Acked-by: Lei Wen Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 1fb3b3a80581..f7040ea8dd4b 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1119,7 +1119,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) clk_put(info->clk); if (mtd) { - mtd_device_unregister(mtd); + nand_release(mtd); kfree(mtd); } return 0; From 82e023ab4e144da7f83fe7e6c93a09be2f30ff07 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 3 Jun 2011 13:15:30 +0800 Subject: [PATCH 0166/1596] mtd: fsmc_nand: fix a memory leak In fsmc_nand_remove, we should call nand_release instead of mtd_device_unregister to properly free bad block table memory and bad block descriptor memory. Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsmc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index e9b275ac381c..8a5f1aa2b286 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -822,7 +822,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (host) { - mtd_device_unregister(&host->mtd); + nand_release(&host->mtd); clk_disable(host->clk); clk_put(host->clk); From 7578ca927b1a2a0445c9a3166d05462b9ffd4c06 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 3 Jun 2011 14:10:22 +0800 Subject: [PATCH 0167/1596] mtd: mtdblock: Use DEFINE_MUTEX() for mtdblks_lock mtdblks_lock can be initialized automatically with DEFINE_MUTEX() rather than explicitly calling mutex_init(). Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdblock.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 3326615ad66b..1976b6c0508d 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -44,7 +44,7 @@ struct mtdblk_dev { enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; }; -static struct mutex mtdblks_lock; +static DEFINE_MUTEX(mtdblks_lock); /* * Cache stuff... @@ -389,8 +389,6 @@ static struct mtd_blktrans_ops mtdblock_tr = { static int __init init_mtdblock(void) { - mutex_init(&mtdblks_lock); - return register_mtd_blktrans(&mtdblock_tr); } From 1676bc18c6648c378029dad365756e12be7da025 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 3 Jun 2011 15:34:33 +0800 Subject: [PATCH 0168/1596] mtd: pxa3xx_nand: remove unused variable 'mtd' Remove unused variable 'mtd' to eliminate below warning. CC drivers/mtd/nand/pxa3xx_nand.o drivers/mtd/nand/pxa3xx_nand.c: In function 'pxa3xx_nand_suspend': drivers/mtd/nand/pxa3xx_nand.c:1167: warning: unused variable 'mtd' drivers/mtd/nand/pxa3xx_nand.c: In function 'pxa3xx_nand_resume': drivers/mtd/nand/pxa3xx_nand.c:1180: warning: unused variable 'mtd' Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/pxa3xx_nand.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index f7040ea8dd4b..e11f926c9335 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1164,7 +1164,6 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; if (info->state) { dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); @@ -1177,7 +1176,6 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) static int pxa3xx_nand_resume(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; nand_writel(info, NDTR0CS0, info->ndtr0cs0); nand_writel(info, NDTR1CS0, info->ndtr1cs0); From 1fc468d5d55a0d9101e482ccb96b1b2879a73882 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:42 +0400 Subject: [PATCH 0169/1596] mtd: mtd_dataflash don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/mtd_dataflash.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 13749d458a31..4d4a9cd10c33 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -677,12 +677,7 @@ add_dataflash_otp(struct spi_device *spi, char *name, pagesize, otp_tag); dev_set_drvdata(&spi->dev, priv); - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] = { "cmdlinepart", NULL, }; - - nr_parts = parse_mtd_partitions(device, part_probes, &parts, - 0); - } + nr_parts = parse_mtd_partitions(device, NULL, &parts, 0); if (nr_parts <= 0 && pdata && pdata->parts) { parts = pdata->parts; From adaf2a5d0887f9a317eca8550e59b0c92876c64f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:43 +0400 Subject: [PATCH 0170/1596] mtd: sst25l don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/sst25l.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 83e80c65d6e7..52eb92edde93 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -423,13 +423,7 @@ static int __devinit sst25l_probe(struct spi_device *spi) flash->mtd.numeraseregions); - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] = {"cmdlinepart", NULL}; - - nr_parts = parse_mtd_partitions(&flash->mtd, - part_probes, - &parts, 0); - } + nr_parts = parse_mtd_partitions(&flash->mtd, NULL, &parts, 0); if (nr_parts <= 0 && data && data->parts) { parts = data->parts; From 3af035c96ac72d2d301f04ad7f253e342a7dc54b Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:44 +0400 Subject: [PATCH 0171/1596] mtd: h720x-flash don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/h720x-flash.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 7f035860a36b..f331a2c94271 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -60,8 +60,6 @@ static struct mtd_partition h720x_partitions[] = { static int nr_mtd_parts; static struct mtd_partition *mtd_parts; -static const char *probes[] = { "cmdlinepart", NULL }; - /* * Initialize FLASH support */ @@ -92,7 +90,7 @@ static int __init h720x_mtd_init(void) if (mymtd) { mymtd->owner = THIS_MODULE; - nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); + nr_mtd_parts = parse_mtd_partitions(mymtd, NULL, &mtd_parts, 0); if (nr_mtd_parts > 0) part_type = "command line"; if (nr_mtd_parts <= 0) { From cec25c7290d1b9d514686be97e9e62c89dd3308f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:45 +0400 Subject: [PATCH 0172/1596] mtd: impa7 don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/impa7.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 404a50cbafa0..2d45a489622e 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -61,7 +61,6 @@ static struct mtd_partition static_partitions[] = static int mtd_parts_nb[NUM_FLASHBANKS]; static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; -static const char *probes[] = { "cmdlinepart", NULL }; static int __init init_impa7(void) { @@ -98,7 +97,7 @@ static int __init init_impa7(void) impa7_mtd[i]->owner = THIS_MODULE; devicesfound++; mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], - probes, + NULL, &mtd_parts[i], 0); if (mtd_parts_nb[i] > 0) { From 8d130a74e40da7dc4c572fbf0ba533fac17f4190 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:46 +0400 Subject: [PATCH 0173/1596] mtd: intel_vr_nor don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/intel_vr_nor.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index d2f47be8754b..fd612c7ec1f6 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -72,11 +72,10 @@ static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p) static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p) { struct mtd_partition *parts; - static const char *part_probes[] = { "cmdlinepart", NULL }; /* register the flash bank */ /* partition the flash bank */ - p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0); + p->nr_parts = parse_mtd_partitions(p->info, NULL, &parts, 0); return mtd_device_register(p->info, parts, p->nr_parts); } From 2ef3855a91300bc0dae0ddc8689e4ee64abe6a8a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:47 +0400 Subject: [PATCH 0174/1596] mtd: rbtx4939-flash don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Artem: tweaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/rbtx4939-flash.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index 761fb459d2c7..5d15b6b32265 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -50,7 +50,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev) } static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; -static const char *part_probe_types[] = { "cmdlinepart", NULL }; static int rbtx4939_flash_probe(struct platform_device *dev) { @@ -107,9 +106,7 @@ static int rbtx4939_flash_probe(struct platform_device *dev) info->mtd->owner = THIS_MODULE; if (err) goto err_out; - - err = parse_mtd_partitions(info->mtd, part_probe_types, - &info->parts, 0); + err = parse_mtd_partitions(info->mtd, NULL, &info->parts, 0); if (err > 0) { mtd_device_register(info->mtd, info->parts, err); info->nr_parts = err; From 2108c3bc632962422b7929e715ed6bbb837ac25c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:48 +0400 Subject: [PATCH 0175/1596] mtd: atmel_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Artem: tweaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/atmel_nand.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 01fb5f0adcf0..47ece8e06e17 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -481,10 +481,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) } } -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif - /* * Probe for the NAND device. */ @@ -655,11 +651,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev) goto err_scan_tail; } -#ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "atmel_nand"; - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partitions, 0); -#endif + num_partitions = parse_mtd_partitions(mtd, NULL, &partitions, 0); if (num_partitions <= 0 && host->board->parts) { partitions = host->board->parts; num_partitions = host->board->num_parts; From caf32f4e8ca84ed1b0570176770f7209e7c304fe Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:49 +0400 Subject: [PATCH 0176/1596] mtd: bcm_umi_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Artem: tweaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/bcm_umi_nand.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index e3ffc4c908e4..b1b7b16a843b 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -52,8 +52,6 @@ static const __devinitconst char gBanner[] = KERN_INFO \ "BCM UMI MTD NAND Driver: 1.00\n"; -const char *part_probes[] = { "cmdlinepart", NULL }; - #if NAND_ECC_BCH static uint8_t scan_ff_pattern[] = { 0xff }; @@ -496,9 +494,8 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) struct mtd_partition *partition_info; board_mtd->name = "bcm_umi-nand"; - nr_partitions = - parse_mtd_partitions(board_mtd, part_probes, - &partition_info, 0); + nr_partitions = parse_mtd_partitions(board_mtd, NULL, + &partition_info, 0); if (nr_partitions <= 0) { printk(KERN_ERR "BCM UMI NAND: Too few partitions - %d\n", From 00205e831326f7fc22888de152b313c89a43a110 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:52 +0400 Subject: [PATCH 0177/1596] mtd: cmx270_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/cmx270_nand.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 6fc043a30d1e..f8f5b7c0daf5 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -50,8 +50,6 @@ static struct mtd_partition partition_info[] = { }; #define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) -const char *part_probes[] = { "cmdlinepart", NULL }; - static u_char cmx270_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; @@ -222,14 +220,13 @@ static int __init cmx270_init(void) goto err_scan; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes, + mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, NULL, &mtd_parts, 0); if (mtd_parts_nb > 0) part_type = "command line"; else mtd_parts_nb = 0; -#endif + if (!mtd_parts_nb) { mtd_parts = partition_info; mtd_parts_nb = NUM_PARTITIONS; From 5987d3f45a3819985eb8f34203a5ca2604f08c06 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:53 +0400 Subject: [PATCH 0178/1596] mtd: cs553x_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/cs553x_nand.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index b35496143e74..b2bdf72a9f19 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -278,8 +278,6 @@ static int is_geode(void) return 0; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - static int __init cs553x_init(void) { int err = -ENXIO; @@ -318,9 +316,7 @@ static int __init cs553x_init(void) if (cs553x_mtd[i]) { /* If any devices registered, return success. Else the last error. */ - mtd_parts_nb = parse_mtd_partitions(cs553x_mtd[i], part_probes, &mtd_parts, 0); - if (mtd_parts_nb > 0) - printk(KERN_NOTICE "Using command line partition definition\n"); + mtd_parts_nb = parse_mtd_partitions(cs553x_mtd[i], NULL, &mtd_parts, 0); mtd_device_register(cs553x_mtd[i], mtd_parts, mtd_parts_nb); err = 0; From 4e243a04c39b009e42ff4a4682ed47b850997dc1 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:54 +0400 Subject: [PATCH 0179/1596] mtd: davinci_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/davinci_nand.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index a4c82b4344ba..0c582ed98e43 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -753,14 +753,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) if (ret < 0) goto err_scan; - if (mtd_has_cmdlinepart()) { - static const char *probes[] __initconst = { - "cmdlinepart", NULL - }; - - mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes, - &mtd_parts, 0); - } + mtd_parts_nb = parse_mtd_partitions(&info->mtd, NULL, &mtd_parts, 0); if (mtd_parts_nb <= 0) { mtd_parts = pdata->parts; From 495e2f41c38c99b2785cd3d99b24b080b20e8eb4 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:55 +0400 Subject: [PATCH 0180/1596] mtd: edb7312 don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/edb7312.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 8400d0f6dada..2f9374b38b90 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -98,8 +98,6 @@ static int ep7312_device_ready(struct mtd_info *mtd) return 1; } -const char *part_probes[] = { "cmdlinepart", NULL }; - /* * Main initialization routine */ @@ -158,7 +156,7 @@ static int __init ep7312_init(void) return -ENXIO; } ep7312_mtd->name = "edb7312-nand"; - mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, &mtd_parts, 0); + mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, NULL, &mtd_parts, 0); if (mtd_parts_nb > 0) part_type = "command line"; else From a8e083246387ffb9a84551fa908a358cacdc2b0c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:56 +0400 Subject: [PATCH 0181/1596] mtd: fsl_upm don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_upm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 23752fd5bc59..7c782ebd0f31 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -158,7 +158,6 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, { int ret; struct device_node *flash_np; - static const char *part_types[] = { "cmdlinepart", NULL, }; fun->chip.IO_ADDR_R = fun->io_base; fun->chip.IO_ADDR_W = fun->io_base; @@ -192,7 +191,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, if (ret) goto err; - ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); + ret = parse_mtd_partitions(&fun->mtd, NULL, &fun->parts, 0); #ifdef CONFIG_MTD_OF_PARTS if (ret == 0) { From 8d3f8bb8093080d4e2b1de096af444b694a16766 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:57 +0400 Subject: [PATCH 0182/1596] mtd: fsmc_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsmc_nand.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 8a5f1aa2b286..a39c224eb12f 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -177,9 +177,6 @@ static struct mtd_partition partition_info_128KB_blk[] = { }, }; -#ifdef CONFIG_MTD_CMDLINE_PARTS -const char *part_probes[] = { "cmdlinepart", NULL }; -#endif /** * struct fsmc_nand_data - structure for FSMC NAND device state @@ -716,15 +713,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * platform data, * default partition information present in driver. */ -#ifdef CONFIG_MTD_CMDLINE_PARTS /* - * Check if partition info passed via command line + * Check for partition info passed */ host->mtd.name = "nand"; - host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes, + host->nr_partitions = parse_mtd_partitions(&host->mtd, NULL, &host->partitions, 0); if (host->nr_partitions <= 0) { -#endif /* * Check if partition info passed via command line */ @@ -769,9 +764,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) } } } -#ifdef CONFIG_MTD_CMDLINE_PARTS } -#endif ret = mtd_device_register(&host->mtd, host->partitions, host->nr_partitions); From e411f52d591fff47a251a213e1f4115dfb356e8d Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:16:58 +0400 Subject: [PATCH 0183/1596] mtd: h1910 don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/h1910.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 02a03e67109c..42f9177e36b1 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -136,14 +136,10 @@ static int __init h1910_init(void) iounmap((void *)nandaddr); return -ENXIO; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, "h1910-nand"); + mtd_parts_nb = parse_mtd_partitions(h1910_nand_mtd, NULL, &mtd_parts, 0); if (mtd_parts_nb > 0) part_type = "command line"; - else - mtd_parts_nb = 0; -#endif - if (mtd_parts_nb == 0) { + else { mtd_parts = partition_info; mtd_parts_nb = NUM_PARTITIONS; part_type = "static"; From bef06150b2c0607edbee8e8c5fd7e882a90a976a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:00 +0400 Subject: [PATCH 0184/1596] mtd: jz4740_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/jz4740_nand.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 6e813daed068..920719cbdb55 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -251,10 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, return 0; } -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = {"cmdline", NULL}; -#endif - static int jz_nand_ioremap_resource(struct platform_device *pdev, const char *name, struct resource **res, void __iomem **base) { @@ -373,10 +369,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) goto err_gpio_free; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partition_info, 0); -#endif + num_partitions = parse_mtd_partitions(mtd, NULL, &partition_info, 0); if (num_partitions <= 0 && pdata) { num_partitions = pdata->num_partitions; partition_info = pdata->partitions; From 0455dfd4c8614ae971202697f6db4d239e0b44c3 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:25:00 +0400 Subject: [PATCH 0185/1596] mtd: lantiq-flash don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Artem: tewaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/lantiq-flash.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index a90cabd7b84d..57ea3fe2296f 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -107,8 +107,6 @@ ltq_copy_to(struct map_info *map, unsigned long to, spin_unlock_irqrestore(&ebu_lock, flags); } -static const char const *part_probe_types[] = { "cmdlinepart", NULL }; - static int __init ltq_mtd_probe(struct platform_device *pdev) { @@ -172,8 +170,7 @@ ltq_mtd_probe(struct platform_device *pdev) cfi->addr_unlock1 ^= 1; cfi->addr_unlock2 ^= 1; - nr_parts = parse_mtd_partitions(ltq_mtd->mtd, - part_probe_types, &parts, 0); + nr_parts = parse_mtd_partitions(ltq_mtd->mtd, NULL, &parts, 0); if (nr_parts > 0) { dev_info(&pdev->dev, "using %d partitions from cmdline", nr_parts); From ac9b0f3662f523e6aeb7669b40269ecbd2fd752b Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:25:01 +0400 Subject: [PATCH 0186/1596] mtd: latch-addr-flash don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Artem: tweaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/latch-addr-flash.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 5936c466e901..09cf704ea02e 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -97,8 +97,6 @@ static void lf_copy_from(struct map_info *map, void *to, static char *rom_probe_types[] = { "cfi_probe", NULL }; -static char *part_probe_types[] = { "cmdlinepart", NULL }; - static int latch_addr_flash_remove(struct platform_device *dev) { struct latch_addr_flash_info *info; @@ -206,8 +204,7 @@ static int __devinit latch_addr_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - err = parse_mtd_partitions(info->mtd, (const char **)part_probe_types, - &info->parts, 0); + err = parse_mtd_partitions(info->mtd, NULL, &info->parts, 0); if (err > 0) { mtd_device_register(info->mtd, info->parts, err); return 0; From 5279fe36fa4c5e3f33b25111c1cbf08386e78d06 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:01 +0400 Subject: [PATCH 0187/1596] mtd: mpc5121_nfc don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/mpc5121_nfc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 2f2c35a7771e..30f78ea8e993 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -131,8 +131,6 @@ struct mpc5121_nfc_prv { static void mpc5121_nfc_done(struct mtd_info *mtd); -static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL }; - /* Read NFC register */ static inline u16 nfc_read(struct mtd_info *mtd, uint reg) { @@ -838,7 +836,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) dev_set_drvdata(dev, mtd); /* Register device in MTD */ - retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0); + retval = parse_mtd_partitions(mtd, NULL, &parts, 0); #ifdef CONFIG_MTD_OF_PARTS if (retval == 0) retval = of_mtd_parse_partitions(dev, dn, &parts); From 2aedf3e982c1b0177710c87e2f199624d07abc8e Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:02 +0400 Subject: [PATCH 0188/1596] mtd: ndfc don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/ndfc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index ea2dea8a9c88..cb66fd79f1fa 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -159,11 +159,6 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) static int ndfc_chip_init(struct ndfc_controller *ndfc, struct device_node *node) { -#ifdef CONFIG_MTD_CMDLINE_PARTS - static const char *part_types[] = { "cmdlinepart", NULL }; -#else - static const char *part_types[] = { NULL }; -#endif struct device_node *flash_np; struct nand_chip *chip = &ndfc->chip; int ret; @@ -204,7 +199,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (ret) goto err; - ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0); + ret = parse_mtd_partitions(&ndfc->mtd, NULL, &ndfc->parts, 0); if (ret < 0) goto err; From f397d8c074c966f61b12c4c554e0aa32704056c7 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:03 +0400 Subject: [PATCH 0189/1596] mtd: omap2 don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/omap2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 0db2c0e7656a..8783c0800b5e 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -94,8 +94,6 @@ #define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) #define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; /* Define some generic bad / good block scan pattern which are used @@ -1103,7 +1101,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) goto out_release_mem_region; } - err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); + err = parse_mtd_partitions(&info->mtd, NULL, &info->parts, 0); if (err > 0) mtd_device_register(&info->mtd, info->parts, err); else if (pdata->parts) From 4ac6b3ef7191c508a356c205b02ab82f5e228d0c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:04 +0400 Subject: [PATCH 0190/1596] mtd: orion_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/orion_nand.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 7794d0680f91..5c55981df3da 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -21,8 +21,6 @@ #include #include -static const char *part_probes[] = { "cmdlinepart", NULL }; - static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *nc = mtd->priv; @@ -132,10 +130,8 @@ static int __init orion_nand_probe(struct platform_device *pdev) goto no_dev; } -#ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "orion_nand"; - num_part = parse_mtd_partitions(mtd, part_probes, &partitions, 0); -#endif + num_part = parse_mtd_partitions(mtd, NULL, &partitions, 0); /* If cmdline partitions have been passed, let them be used */ if (num_part <= 0) { num_part = board->nr_parts; From 16b206e62f9b43ba864571a6808844aaddea7479 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:05 +0400 Subject: [PATCH 0191/1596] mtd: ppchameleonevb don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/ppchameleonevb.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 3bbb796b451c..93766336ab79 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -99,8 +99,6 @@ static struct mtd_partition partition_info_evb[] = { #define NUM_PARTITIONS 1 -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, const char *mtd_id); - /* * hardware specific access to control-lines */ @@ -187,9 +185,6 @@ static int ppchameleonevb_device_ready(struct mtd_info *minfo) } #endif -const char *part_probes[] = { "cmdlinepart", NULL }; -const char *part_probes_evb[] = { "cmdlinepart", NULL }; - /* * Main initialization routine */ @@ -281,7 +276,7 @@ static int __init ppchameleonevb_init(void) #endif ppchameleon_mtd->name = "ppchameleon-nand"; - mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, part_probes, &mtd_parts, 0); + mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, NULL, &mtd_parts, 0); if (mtd_parts_nb > 0) part_type = "command line"; else @@ -382,7 +377,7 @@ static int __init ppchameleonevb_init(void) } ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME; - mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &mtd_parts, 0); + mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, NULL, &mtd_parts, 0); if (mtd_parts_nb > 0) part_type = "command line"; else From c842f570a6e3ac002389ab7154084e32f4f5021a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:06 +0400 Subject: [PATCH 0192/1596] mtd: pxa3xx_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/pxa3xx_nand.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index e11f926c9335..c7da3c8be9d6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1129,6 +1129,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; + struct mtd_partition *parts; + int nr_parts; pdata = pdev->dev.platform_data; if (!pdata) { @@ -1146,16 +1148,11 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) return -ENODEV; } - if (mtd_has_cmdlinepart()) { - const char *probes[] = { "cmdlinepart", NULL }; - struct mtd_partition *parts; - int nr_parts; - nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0); + nr_parts = parse_mtd_partitions(info->mtd, NULL, &parts, 0); - if (nr_parts) - return mtd_device_register(info->mtd, parts, nr_parts); - } + if (nr_parts) + return mtd_device_register(info->mtd, parts, nr_parts); return mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); } From 5b2efbdf70c74dcab575103c547ae27a71daba4c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:07 +0400 Subject: [PATCH 0193/1596] mtd: s3c2410 don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/s3c2410.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index ec280798e221..17954baf12cd 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -744,7 +744,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) return 0; } -const char *part_probes[] = { "cmdlinepart", NULL }; static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *mtd, struct s3c2410_nand_set *set) @@ -756,7 +755,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, return mtd_device_register(&mtd->mtd, NULL, 0); mtd->mtd.name = set->name; - nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, &part_info, 0); + nr_part = parse_mtd_partitions(&mtd->mtd, NULL, &part_info, 0); if (nr_part <= 0 && set->nr_partitions > 0) { nr_part = set->nr_partitions; From a4c93614fded8ef0be90fca6a619d3c9c3e9552f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:08 +0400 Subject: [PATCH 0194/1596] mtd: sharpsl don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/sharpsl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 19e24ed089ea..b3377f88326e 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -103,8 +103,6 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, return readb(sharpsl->io + ECCCNTR) != 0; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* * Main initialization routine */ @@ -184,7 +182,7 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) /* Register the partitions */ sharpsl->mtd.name = "sharpsl-nand"; - nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0); + nr_partitions = parse_mtd_partitions(&sharpsl->mtd, NULL, &sharpsl_partition_info, 0); if (nr_partitions <= 0) { nr_partitions = data->nr_partitions; sharpsl_partition_info = data->partitions; From 7221eb1296b3ebb0038dabeb88fe17a4fc62e920 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:09 +0400 Subject: [PATCH 0195/1596] mtd: socrates_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Artem: tweaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/socrates_nand.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index ca2d0555729e..9023ac833fcf 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -155,8 +155,6 @@ static int socrates_nand_device_ready(struct mtd_info *mtd) return 1; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* * Probe for the NAND device. */ @@ -225,14 +223,11 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) goto out; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partitions, 0); + num_partitions = parse_mtd_partitions(mtd, NULL, &partitions, 0); if (num_partitions < 0) { res = num_partitions; goto release; } -#endif if (num_partitions == 0) { num_partitions = of_mtd_parse_partitions(&ofdev->dev, From d845c3eebc1efea59c74a63c028f36051a4d0d8f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:10 +0400 Subject: [PATCH 0196/1596] mtd: tmio_nand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/tmio_nand.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 11e8371b5683..b6ffad64cda5 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -121,9 +121,6 @@ struct tmio_nand { #define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd) -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif /*--------------------------------------------------------------------------*/ @@ -461,9 +458,7 @@ static int tmio_probe(struct platform_device *dev) goto err_scan; } /* Register the partitions */ -#ifdef CONFIG_MTD_CMDLINE_PARTS - nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0); -#endif + nbparts = parse_mtd_partitions(mtd, NULL, &parts, 0); if (nbparts <= 0 && data) { parts = data->partition; nbparts = data->num_partitions; From abfc7d2b94e650c18965e62fe74e457b96b4865a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:11 +0400 Subject: [PATCH 0197/1596] mtd: txx9ndfmc don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/txx9ndfmc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index bfba4e39a6c5..91b05b9a9086 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -287,7 +287,6 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd) static int __init txx9ndfmc_probe(struct platform_device *dev) { struct txx9ndfmc_platform_data *plat = dev->dev.platform_data; - static const char *probes[] = { "cmdlinepart", NULL }; int hold, spw; int i; struct txx9ndfmc_drvdata *drvdata; @@ -393,7 +392,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) } mtd->name = txx9_priv->mtdname; - nr_parts = parse_mtd_partitions(mtd, probes, + nr_parts = parse_mtd_partitions(mtd, NULL, &drvdata->parts[i], 0); mtd_device_register(mtd, drvdata->parts[i], nr_parts); drvdata->mtds[i] = mtd; From 3d4ae3b2eab1d95a944162b047533d74cfcb8def Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:12 +0400 Subject: [PATCH 0198/1596] mtd: onenand/generic don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/generic.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 2d70d354d846..bca1c496135f 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -30,8 +30,6 @@ */ #define DRIVER_NAME "onenand-flash" -static const char *part_probes[] = { "cmdlinepart", NULL, }; - struct onenand_info { struct mtd_info mtd; struct mtd_partition *parts; @@ -73,7 +71,7 @@ static int __devinit generic_onenand_probe(struct platform_device *pdev) goto out_iounmap; } - err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); + err = parse_mtd_partitions(&info->mtd, NULL, &info->parts, 0); if (err > 0) mtd_device_register(&info->mtd, info->parts, err); else if (err <= 0 && pdata && pdata->parts) From 70f438c61636a194d7c3fa341fa72353ba0090f6 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:13 +0400 Subject: [PATCH 0199/1596] mtd: onenand/omap2 don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/omap2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 0d9073d4e417..5ca2053f6027 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -67,8 +67,6 @@ struct omap2_onenand { struct regulator *regulator; }; -static const char *part_probes[] = { "cmdlinepart", NULL, }; - static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) { struct omap2_onenand *c = data; @@ -754,7 +752,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) if ((r = onenand_scan(&c->mtd, 1)) < 0) goto err_release_regulator; - r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); + r = parse_mtd_partitions(&c->mtd, NULL, &c->parts, 0); if (r > 0) r = mtd_device_register(&c->mtd, c->parts, r); else if (pdata->parts != NULL) From 18f8eb1b23619736872740f8c4697b6534a0524b Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 20:17:14 +0400 Subject: [PATCH 0200/1596] mtd: samsung/onenand don't specify default parsing options Since 'cmdline, NULL' is now a default for parse_mtd_partitions, don't specify this in every driver, instead pass NULL to force parse_mtd_partitions to use default. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/samsung.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 3306b5b3c736..78a08eae6adf 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -157,8 +157,6 @@ struct s3c_onenand { static struct s3c_onenand *onenand; -static const char *part_probes[] = { "cmdlinepart", NULL, }; - static inline int s3c_read_reg(int offset) { return readl(onenand->base + offset); @@ -1017,7 +1015,7 @@ static int s3c_onenand_probe(struct platform_device *pdev) if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ) dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n"); - err = parse_mtd_partitions(mtd, part_probes, &onenand->parts, 0); + err = parse_mtd_partitions(mtd, NULL, &onenand->parts, 0); if (err > 0) mtd_device_register(mtd, onenand->parts, err); else if (err <= 0 && pdata && pdata->parts) From 8b6e50c9eba8bf44b2dfd931d359706a461d2cfd Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 25 May 2011 14:59:01 -0700 Subject: [PATCH 0201/1596] mtd: nand: multi-line comment style fixups Artem: while on it, do other commentaries clean-ups: 1. Start one-line comments with capital letter and no dot at the end 2. Turn sparse multi-line comments into one-line comments 3. Change "phrase ?" to "phrase?" and the same with "!". 4. Remove tabs from the kerneldoc parameters comments - they are mixed with tabs often, and inconsistent. 5. Put dot at the end of descriptions in kerneldoc comments. 6. Some other small commentaries clean-ups Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 703 +++++++++++++++++------------------ drivers/mtd/nand/nand_bbt.c | 365 +++++++++--------- 2 files changed, 521 insertions(+), 547 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1380bf6c44c7..1525cd01dacd 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -136,9 +136,9 @@ static int check_offs_len(struct mtd_info *mtd, /** * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Deselect, release chip lock and wake up anyone waiting on the device + * Deselect, release chip lock and wake up anyone waiting on the device. */ static void nand_release_device(struct mtd_info *mtd) { @@ -157,9 +157,9 @@ static void nand_release_device(struct mtd_info *mtd) /** * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 8bit buswith + * Default read function for 8bit buswith. */ static uint8_t nand_read_byte(struct mtd_info *mtd) { @@ -169,10 +169,9 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) /** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 16bit buswith with - * endianess conversion + * Default read function for 16bit buswith with endianess conversion. */ static uint8_t nand_read_byte16(struct mtd_info *mtd) { @@ -182,10 +181,9 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) /** * nand_read_word - [DEFAULT] read one word from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 16bit buswith without - * endianess conversion + * Default read function for 16bit buswith without endianess conversion. */ static u16 nand_read_word(struct mtd_info *mtd) { @@ -195,8 +193,8 @@ static u16 nand_read_word(struct mtd_info *mtd) /** * nand_select_chip - [DEFAULT] control CE line - * @mtd: MTD device structure - * @chipnr: chipnumber to select, -1 for deselect + * @mtd: MTD device structure + * @chipnr: chipnumber to select, -1 for deselect * * Default select function for 1 chip devices. */ @@ -218,11 +216,11 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) /** * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write * - * Default write function for 8bit buswith + * Default write function for 8bit buswith. */ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -235,11 +233,11 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read * - * Default read function for 8bit buswith + * Default read function for 8bit buswith. */ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -252,11 +250,11 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) /** * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare * - * Default verify function for 8bit buswith + * Default verify function for 8bit buswith. */ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -271,11 +269,11 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write * - * Default write function for 16bit buswith + * Default write function for 16bit buswith. */ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -291,11 +289,11 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read * - * Default read function for 16bit buswith + * Default read function for 16bit buswith. */ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -310,11 +308,11 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) /** * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare * - * Default verify function for 16bit buswith + * Default verify function for 16bit buswith. */ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -332,9 +330,9 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected * * Check, if the block is bad. */ @@ -384,11 +382,11 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /** * nand_default_block_markbad - [DEFAULT] mark a block bad - * @mtd: MTD device structure - * @ofs: offset from device start + * @mtd: MTD device structure + * @ofs: offset from device start * - * This is the default implementation, which can be overridden by - * a hardware specific driver. + * This is the default implementation, which can be overridden by a hardware + * specific driver. */ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) { @@ -404,7 +402,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) if (chip->bbt) chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); - /* Do we have a flash based bad block table ? */ + /* Do we have a flash based bad block table? */ if (chip->bbt_options & NAND_BBT_USE_FLASH) ret = nand_update_bbt(mtd, ofs); else { @@ -439,16 +437,16 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /** * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd: MTD device structure - * Check, if the device is write protected + * @mtd: MTD device structure * - * The function expects, that the device is already selected + * Check, if the device is write protected. The function expects, that the + * device is already selected. */ static int nand_check_wp(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - /* broken xD cards report WP despite being writable */ + /* Broken xD cards report WP despite being writable */ if (chip->options & NAND_BROKEN_XD) return 0; @@ -459,10 +457,10 @@ static int nand_check_wp(struct mtd_info *mtd) /** * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected - * @allowbbt: 1, if its allowed to access the bbt area + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected + * @allowbbt: 1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. @@ -481,8 +479,8 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, /** * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. - * @mtd: MTD device structure - * @timeo: Timeout + * @mtd: MTD device structure + * @timeo: Timeout * * Helper function for nand_wait_ready used when needing to wait in interrupt * context. @@ -501,10 +499,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) } } -/* - * Wait for the ready pin, after a command - * The timeout is catched later. - */ +/* Wait for the ready pin, after a command. The timeout is catched later */ void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; @@ -515,7 +510,7 @@ void nand_wait_ready(struct mtd_info *mtd) return panic_nand_wait_ready(mtd, 400); led_trigger_event(nand_led_trigger, LED_FULL); - /* wait until command is processed or timeout occures */ + /* Wait until command is processed or timeout occures */ do { if (chip->dev_ready(mtd)) break; @@ -527,13 +522,13 @@ EXPORT_SYMBOL_GPL(nand_wait_ready); /** * nand_command - [DEFAULT] Send command to NAND device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none * - * Send command to NAND device. This function is used for small page - * devices (256/512 Bytes per page) + * Send command to NAND device. This function is used for small page devices + * (256/512 Bytes per page). */ static void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -541,9 +536,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, register struct nand_chip *chip = mtd->priv; int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; - /* - * Write out the command to the device. - */ + /* Write out the command to the device */ if (command == NAND_CMD_SEQIN) { int readcmd; @@ -563,9 +556,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, } chip->cmd_ctrl(mtd, command, ctrl); - /* - * Address cycle, when necessary - */ + /* Address cycle, when necessary */ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; /* Serially input address */ if (column != -1) { @@ -586,8 +577,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* - * program and erase have their own busy handlers - * status and sequential in needs no delay + * Program and erase have their own busy handlers status and sequential + * in needs no delay */ switch (command) { @@ -621,8 +612,10 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, return; } } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ ndelay(100); nand_wait_ready(mtd); @@ -630,10 +623,10 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, /** * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page * devices We dont have the separate regions as we have in the small page @@ -679,8 +672,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* - * program and erase have their own busy handlers - * status, sequential in, and deplete1 need no delay + * Program and erase have their own busy handlers status, sequential + * in, and deplete1 need no delay. */ switch (command) { @@ -694,14 +687,12 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, case NAND_CMD_DEPLETE1: return; - /* - * read error status commands require only a short delay - */ case NAND_CMD_STATUS_ERROR: case NAND_CMD_STATUS_ERROR0: case NAND_CMD_STATUS_ERROR1: case NAND_CMD_STATUS_ERROR2: case NAND_CMD_STATUS_ERROR3: + /* Read error status commands require only a short delay */ udelay(chip->chip_delay); return; @@ -735,7 +726,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, default: /* * If we don't have access to the busy pin, we apply the given - * command delay + * command delay. */ if (!chip->dev_ready) { udelay(chip->chip_delay); @@ -743,8 +734,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, } } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ ndelay(100); nand_wait_ready(mtd); @@ -752,9 +745,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, /** * panic_nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested * * Used when in panic, no locks are taken. */ @@ -768,9 +761,9 @@ static void panic_nand_get_device(struct nand_chip *chip, /** * nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ @@ -808,10 +801,10 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) } /** - * panic_nand_wait - [GENERIC] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure - * @timeo: Timeout + * panic_nand_wait - [GENERIC] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure + * @timeo: timeout * * Wait for command done. This is a helper function for nand_wait used when * we are in interrupt context. May happen when in panic and trying to write @@ -834,13 +827,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure + * nand_wait - [DEFAULT] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs + * Wait for command done. This applies to erase and program only. Erase can + * take up to 400ms and program up to 20ms according to general NAND and + * SmartMedia specs. */ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) { @@ -855,8 +848,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) led_trigger_event(nand_led_trigger, LED_FULL); - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in any + * case on any machine. + */ ndelay(100); if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) @@ -886,16 +881,15 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) /** * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock - * @invert: when = 0, unlock the range of blocks within the lower and - * upper boundary address - * when = 1, unlock the range of blocks outside the boundaries - * of the lower and upper boundary address + * @invert: when = 0, unlock the range of blocks within the lower and + * upper boundary address + * when = 1, unlock the range of blocks outside the boundaries + * of the lower and upper boundary address * - * return - unlock status + * Returs unlock status. */ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len, int invert) @@ -927,12 +921,11 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, /** * nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock * - * return - unlock status + * Returns unlock status. */ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { @@ -976,18 +969,16 @@ EXPORT_SYMBOL(nand_unlock); /** * nand_lock - [REPLACEABLE] locks all blocks present in the device - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock * - * return - lock status - * - * This feature is not supported in many NAND parts. 'Micron' NAND parts - * do have this feature, but it allows only to lock all blocks, not for - * specified range for block. + * This feature is not supported in many NAND parts. 'Micron' NAND parts do + * have this feature, but it allows only to lock all blocks, not for specified + * range for block. Implementing 'lock' feature by making use of 'unlock', for + * now. * - * Implementing 'lock' feature by making use of 'unlock', for now. + * Returns lock status. */ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { @@ -1042,12 +1033,13 @@ EXPORT_SYMBOL(nand_lock); /** * nand_read_page_raw - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ecc controllers, which use a special oob + * layout. */ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1059,10 +1051,10 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * * We need a special oob layout and handling even when OOB isn't used. */ @@ -1102,10 +1094,10 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, /** * nand_read_page_swecc - [REPLACABLE] software ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read */ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1143,11 +1135,11 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @data_offs: offset of requested data within the page - * @readlen: data length - * @bufpoi: buffer to store read data + * @mtd: mtd info structure + * @chip: nand chip info structure + * @data_offs: offset of requested data within the page + * @readlen: data length + * @bufpoi: buffer to store read data */ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) @@ -1160,12 +1152,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; int index = 0; - /* Column address wihin the page aligned to ECC size (256bytes). */ + /* Column address wihin the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size; end_step = (data_offs + readlen - 1) / chip->ecc.size; num_steps = end_step - start_step + 1; - /* Data size aligned to ECC ecc.size*/ + /* Data size aligned to ECC ecc.size */ datafrag_len = num_steps * chip->ecc.size; eccfrag_len = num_steps * chip->ecc.bytes; @@ -1177,13 +1169,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, p = bufpoi + data_col_addr; chip->read_buf(mtd, p, datafrag_len); - /* Calculate ECC */ + /* Calculate ECC */ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); - /* The performance is faster if to position offsets - according to ecc.pos. Let make sure here that - there are no gaps in ecc positions */ + /* + * The performance is faster if we position offsets according to + * ecc.pos. Let's make sure that there are no gaps in ecc positions. + */ for (i = 0; i < eccfrag_len - 1; i++) { if (eccpos[i + start_step * chip->ecc.bytes] + 1 != eccpos[i + start_step * chip->ecc.bytes + 1]) { @@ -1195,8 +1188,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); } else { - /* send the command to read the particular ecc bytes */ - /* take care about buswidth alignment in read_buf */ + /* + * Send the command to read the particular ecc bytes take care + * about buswidth alignment in read_buf. + */ index = start_step * chip->ecc.bytes; aligned_pos = eccpos[index] & ~(busw - 1); @@ -1230,12 +1225,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Not for syndrome calculating ecc controllers which need a special oob layout + * Not for syndrome calculating ecc controllers which need a special oob + * layout. */ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1275,17 +1271,16 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Hardware ECC for large page chips, require OOB to be read first. - * For this ECC mode, the write_page method is re-used from ECC_HW. - * These methods read/write ECC from the OOB area, unlike the - * ECC_HW_SYNDROME support with multiple ECC steps, follows the - * "infix ECC" scheme and reads/writes ECC from the data area, by - * overwriting the NAND manufacturer bad block markings. + * Hardware ECC for large page chips, require OOB to be read first. For this + * ECC mode, the write_page method is re-used from ECC_HW. These methods + * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with + * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from + * the data area, by overwriting the NAND manufacturer bad block markings. */ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1324,13 +1319,13 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, /** * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling. */ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1379,10 +1374,10 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_transfer_oob - [Internal] Transfer oob to client buffer - * @chip: nand chip structure - * @oob: oob destination address - * @ops: oob ops structure - * @len: size of oob to transfer + * @chip: nand chip structure + * @oob: oob destination address + * @ops: oob ops structure + * @len: size of oob to transfer */ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) @@ -1400,7 +1395,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0 ? */ + /* Read request not from offset 0? */ if (unlikely(roffs)) { if (roffs >= free->length) { roffs -= free->length; @@ -1427,10 +1422,9 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, /** * nand_do_read_ops - [Internal] Read data with ECC - * - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob ops structure + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob ops structure * * Internal function. Called with chip held. */ @@ -1467,7 +1461,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); - /* Is the current page in the buffer ? */ + /* Is the current page in the buffer? */ if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; @@ -1533,7 +1527,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (!readlen) break; - /* For subsequent reads align to page boundary. */ + /* For subsequent reads align to page boundary */ col = 0; /* Increment page address */ realpage++; @@ -1546,8 +1540,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. + /* + * Check, if the chip supports auto page increment or if we + * have hit a block boundary. */ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) sndcmd = 1; @@ -1568,13 +1563,13 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /** * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc - * @mtd: MTD device structure - * @from: offset to read from - * @len: number of bytes to read - * @retlen: pointer to variable to store the number of read bytes - * @buf: the databuffer to put data + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data * - * Get hold of the chip and call nand_do_read + * Get hold of the chip and call nand_do_read. */ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) @@ -1605,10 +1600,10 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, /** * nand_read_oob_std - [REPLACABLE] the most common OOB data read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not */ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) @@ -1624,10 +1619,10 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC * with syndromes - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not */ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) @@ -1662,9 +1657,9 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_write_oob_std - [REPLACABLE] the most common OOB data write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write */ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) @@ -1685,10 +1680,10 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC - * with syndrome - only for large page flash ! - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write + * with syndrome - only for large page flash + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write */ static int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page) @@ -1744,11 +1739,11 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, /** * nand_do_read_oob - [Intern] NAND read out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operations description structure + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operations description structure * - * NAND read out-of-band data from the spare area + * NAND read out-of-band data from the spare area. */ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) @@ -1824,8 +1819,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. + /* + * Check, if the chip supports auto page increment or if we + * have hit a block boundary. */ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) sndcmd = 1; @@ -1837,11 +1833,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, /** * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure * - * NAND read data and/or out-of-band data + * NAND read data and/or out-of-band data. */ static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) @@ -1883,11 +1879,12 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, /** * nand_write_page_raw - [Intern] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ecc controllers, which use a special oob + * layout. */ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1898,9 +1895,9 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_write_page_raw_syndrome - [Intern] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * * We need a special oob layout and handling even when ECC isn't checked. */ @@ -1937,9 +1934,9 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, } /** * nand_write_page_swecc - [REPLACABLE] software ecc based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer */ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1963,9 +1960,9 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer */ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1991,12 +1988,12 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling. */ static void nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -2035,12 +2032,12 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, /** * nand_write_page - [REPLACEABLE] write one page - * @mtd: MTD device structure - * @chip: NAND chip descriptor - * @buf: the data to write - * @page: page number to write - * @cached: cached programming - * @raw: use _raw version of write_page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @buf: the data to write + * @page: page number to write + * @cached: cached programming + * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, int cached, int raw) @@ -2056,7 +2053,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, /* * Cached progamming disabled for now, Not sure if its worth the - * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) + * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s). */ cached = 0; @@ -2066,7 +2063,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, status = chip->waitfunc(mtd, chip); /* * See if operation failed and additional status checks are - * available + * available. */ if ((status & NAND_STATUS_FAIL) && (chip->errstat)) status = chip->errstat(mtd, chip, FL_WRITING, status, @@ -2091,10 +2088,10 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_fill_oob - [Internal] Transfer client buffer to oob - * @chip: nand chip structure - * @oob: oob data buffer - * @len: oob data write length - * @ops: oob ops structure + * @chip: nand chip structure + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure */ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, struct mtd_oob_ops *ops) @@ -2112,7 +2109,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { - /* Write request not from offset 0 ? */ + /* Write request not from offset 0? */ if (unlikely(woffs)) { if (woffs >= free->length) { woffs -= free->length; @@ -2141,11 +2138,11 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, /** * nand_do_write_ops - [Internal] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operations description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operations description structure * - * NAND write with ECC + * NAND write with ECC. */ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2166,7 +2163,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (!writelen) return 0; - /* reject writes, which are not page aligned */ + /* Reject writes, which are not page aligned */ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { printk(KERN_NOTICE "%s: Attempt to write not " "page aligned data\n", __func__); @@ -2208,7 +2205,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; - /* Partial page write ? */ + /* Partial page write? */ if (unlikely(column || writelen < (mtd->writesize - 1))) { cached = 0; bytes = min_t(int, bytes - column, (int) writelen); @@ -2254,11 +2251,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /** * panic_nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write * * NAND write with ECC. Used when performing writes in interrupt context, this * may for example be called by mtdoops when writing an oops while in panic. @@ -2275,10 +2272,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, if (!len) return 0; - /* Wait for the device to get ready. */ + /* Wait for the device to get ready */ panic_nand_wait(mtd, chip, 400); - /* Grab the device. */ + /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); chip->ops.len = len; @@ -2293,13 +2290,13 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, /** * nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write * - * NAND write with ECC + * NAND write with ECC. */ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) @@ -2330,11 +2327,11 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, /** * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure * - * NAND write out-of-band + * NAND write out-of-band. */ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2410,9 +2407,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, /** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure */ static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2453,10 +2450,10 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, /** * single_erease_cmd - [GENERIC] NAND standard block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased + * @mtd: MTD device structure + * @page: the page address of the block which will be erased * - * Standard erase command for NAND chips + * Standard erase command for NAND chips. */ static void single_erase_cmd(struct mtd_info *mtd, int page) { @@ -2468,11 +2465,10 @@ static void single_erase_cmd(struct mtd_info *mtd, int page) /** * multi_erease_cmd - [GENERIC] AND specific block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased + * @mtd: MTD device structure + * @page: the page address of the block which will be erased * - * AND multi block erase command function - * Erase 4 consecutive blocks + * AND multi block erase command function. Erase 4 consecutive blocks. */ static void multi_erase_cmd(struct mtd_info *mtd, int page) { @@ -2487,10 +2483,10 @@ static void multi_erase_cmd(struct mtd_info *mtd, int page) /** * nand_erase - [MTD Interface] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction + * @mtd: MTD device structure + * @instr: erase instruction * - * Erase one ore more blocks + * Erase one ore more blocks. */ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) { @@ -2500,11 +2496,11 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) #define BBT_PAGE_MASK 0xffffff3f /** * nand_erase_nand - [Internal] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction - * @allowbbt: allow erasing the bbt area + * @mtd: MTD device structure + * @instr: erase instruction + * @allowbbt: allow erasing the bbt area * - * Erase one ore more blocks + * Erase one ore more blocks. */ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) @@ -2549,7 +2545,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, * If BBT requires refresh, set the BBT page mask to see if the BBT * should be rewritten. Otherwise the mask is set to 0xffffffff which * can not be matched. This is also done when the bbt is actually - * erased to avoid recusrsive updates + * erased to avoid recusrsive updates. */ if (chip->options & BBT_AUTO_REFRESH && !allowbbt) bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; @@ -2560,9 +2556,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, instr->state = MTD_ERASING; while (len) { - /* - * heck if we have a bad block, we do not erase bad blocks ! - */ + /* Heck if we have a bad block, we do not erase bad blocks! */ if (nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { printk(KERN_WARNING "%s: attempt to erase a bad block " @@ -2573,7 +2567,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * Invalidate the page cache, if we erase the block which - * contains the current cached page + * contains the current cached page. */ if (page <= chip->pagebuf && chip->pagebuf < (page + pages_per_block)) @@ -2603,7 +2597,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh, set the BBT rewrite flag to the - * page being erased + * page being erased. */ if (bbt_masked_page != 0xffffffff && (page & BBT_PAGE_MASK) == bbt_masked_page) @@ -2622,7 +2616,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh and BBT-PERCHIP, set the BBT - * page mask to see if this BBT should be rewritten + * page mask to see if this BBT should be rewritten. */ if (bbt_masked_page != 0xffffffff && (chip->bbt_td->options & NAND_BBT_PERCHIP)) @@ -2645,7 +2639,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh and erase was successful, rewrite any - * selected bad block tables + * selected bad block tables. */ if (bbt_masked_page == 0xffffffff || ret) return ret; @@ -2653,7 +2647,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, for (chipnr = 0; chipnr < chip->numchips; chipnr++) { if (!rewrite_bbt[chipnr]) continue; - /* update the BBT for chip */ + /* Update the BBT for chip */ DEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " "(%d:0x%0llx 0x%0x)\n", __func__, chipnr, rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); @@ -2666,9 +2660,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /** * nand_sync - [MTD Interface] sync - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Sync is actually a wait for chip ready function + * Sync is actually a wait for chip ready function. */ static void nand_sync(struct mtd_info *mtd) { @@ -2684,8 +2678,8 @@ static void nand_sync(struct mtd_info *mtd) /** * nand_block_isbad - [MTD Interface] Check if block at offset is bad - * @mtd: MTD device structure - * @offs: offset relative to mtd start + * @mtd: MTD device structure + * @offs: offset relative to mtd start */ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) { @@ -2698,8 +2692,8 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) /** * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad - * @mtd: MTD device structure - * @ofs: offset relative to mtd start + * @mtd: MTD device structure + * @ofs: offset relative to mtd start */ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) { @@ -2708,7 +2702,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) ret = nand_block_isbad(mtd, ofs); if (ret) { - /* If it was bad already, return success and do nothing. */ + /* If it was bad already, return success and do nothing */ if (ret > 0) return 0; return ret; @@ -2719,7 +2713,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) /** * nand_suspend - [MTD Interface] Suspend the NAND flash - * @mtd: MTD device structure + * @mtd: MTD device structure */ static int nand_suspend(struct mtd_info *mtd) { @@ -2730,7 +2724,7 @@ static int nand_suspend(struct mtd_info *mtd) /** * nand_resume - [MTD Interface] Resume the NAND flash - * @mtd: MTD device structure + * @mtd: MTD device structure */ static void nand_resume(struct mtd_info *mtd) { @@ -2743,9 +2737,7 @@ static void nand_resume(struct mtd_info *mtd) "in suspended state\n", __func__); } -/* - * Set default functions - */ +/* Set default functions */ static void nand_set_defaults(struct nand_chip *chip, int busw) { /* check for proper chip_delay setup, set 20us if not */ @@ -2787,23 +2779,21 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) } -/* - * sanitize ONFI strings so we can safely print them - */ +/* Sanitize ONFI strings so we can safely print them */ static void sanitize_string(uint8_t *s, size_t len) { ssize_t i; - /* null terminate */ + /* Null terminate */ s[len - 1] = 0; - /* remove non printable chars */ + /* Remove non printable chars */ for (i = 0; i < len - 1; i++) { if (s[i] < ' ' || s[i] > 127) s[i] = '?'; } - /* remove trailing spaces */ + /* Remove trailing spaces */ strim(s); } @@ -2820,7 +2810,7 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) } /* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int busw) @@ -2829,7 +2819,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int i; int val; - /* try ONFI for unknow chip or LP */ + /* Try ONFI for unknow chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') @@ -2849,7 +2839,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, if (i == 3) return 0; - /* check version */ + /* Check version */ val = le16_to_cpu(p->revision); if (val & (1 << 5)) chip->onfi_version = 23; @@ -2890,7 +2880,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, } /* - * Get the flash and manufacturer id and lookup if the type is supported + * Get the flash and manufacturer id and lookup if the type is supported. */ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, @@ -2907,7 +2897,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) - * after power-up + * after power-up. */ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); @@ -2918,7 +2908,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, *maf_id = chip->read_byte(mtd); *dev_id = chip->read_byte(mtd); - /* Try again to make sure, as some systems the bus-hold or other + /* + * Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a * possibly credible NAND flash to appear. If the two results do * not match, ignore the device completely. @@ -2967,7 +2958,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chipsize = (uint64_t)type->chipsize << 20; if (!type->pagesize && chip->init_size) { - /* set the pagesize, oobsize, erasesize by the driver*/ + /* Set the pagesize, oobsize, erasesize by the driver */ busw = chip->init_size(mtd, chip, id_data); } else if (!type->pagesize) { int extid; @@ -3027,7 +3018,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, } } else { /* - * Old devices have chip data hardcoded in the device id table + * Old devices have chip data hardcoded in the device id table. */ mtd->erasesize = type->erasesize; mtd->writesize = type->pagesize; @@ -3037,7 +3028,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Check for Spansion/AMD ID + repeating 5th, 6th byte since * some Spansion chips have erasesize that conflicts with size - * listed in nand_ids table + * listed in nand_ids table. * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) */ if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && @@ -3051,15 +3042,16 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->options &= ~NAND_CHIPOPTIONS_MSK; chip->options |= type->options & NAND_CHIPOPTIONS_MSK; - /* Check if chip is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. + /* + * Check if chip is not a Samsung device. Do not clear the + * options for chips which do not have an extended id. */ if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; ident_done: /* - * Set chip as a default. Board drivers can override it, if necessary + * Set chip as a default. Board drivers can override it, if necessary. */ chip->options |= NAND_NO_AUTOINCR; @@ -3071,7 +3063,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Check, if buswidth is correct. Hardware drivers should set - * chip correct ! + * chip correct! */ if (busw != (chip->options & NAND_BUSWIDTH_16)) { printk(KERN_INFO "NAND device: Manufacturer ID:" @@ -3085,7 +3077,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* Calculate the address shift from the page size */ chip->page_shift = ffs(mtd->writesize) - 1; - /* Convert chipsize to number of pages per chip -1. */ + /* Convert chipsize to number of pages per chip -1 */ chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; chip->bbt_erase_shift = chip->phys_erase_shift = @@ -3131,7 +3123,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, else chip->erase_cmd = single_erase_cmd; - /* Do not replace user supplied command function ! */ + /* Do not replace user supplied command function! */ if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; @@ -3145,12 +3137,12 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /** * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * @table: Alternative NAND ID table + * @mtd: MTD device structure + * @maxchips: number of chips to scan for + * @table: alternative NAND ID table * - * This is the first phase of the normal nand_scan() function. It - * reads the flash ID and sets up MTD fields accordingly. + * This is the first phase of the normal nand_scan() function. It reads the + * flash ID and sets up MTD fields accordingly. * * The mtd->owner field must be set to the module of the caller. */ @@ -3203,11 +3195,11 @@ EXPORT_SYMBOL(nand_scan_ident); /** * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure + * @mtd: MTD device structure * - * This is the second phase of the normal nand_scan() function. It - * fills out all the uninitialized function pointers with the defaults - * and scans for a bad block table if appropriate. + * This is the second phase of the normal nand_scan() function. It fills out + * all the uninitialized function pointers with the defaults and scans for a + * bad block table if appropriate. */ int nand_scan_tail(struct mtd_info *mtd) { @@ -3223,7 +3215,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->oob_poi = chip->buffers->databuf + mtd->writesize; /* - * If no default placement scheme is given, select an appropriate one + * If no default placement scheme is given, select an appropriate one. */ if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { switch (mtd->oobsize) { @@ -3250,7 +3242,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->write_page = nand_write_page; /* - * check ECC mode, default to software if 3byte/512byte hardware ECC is + * Check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ @@ -3267,7 +3259,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.read_page = nand_read_page_hwecc_oob_first; case NAND_ECC_HW: - /* Use standard hwecc read page function ? */ + /* Use standard hwecc read page function? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc; if (!chip->ecc.write_page) @@ -3292,7 +3284,7 @@ int nand_scan_tail(struct mtd_info *mtd) "Hardware ECC not possible\n"); BUG(); } - /* Use standard syndrome read/write page function ? */ + /* Use standard syndrome read/write page function? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_syndrome; if (!chip->ecc.write_page) @@ -3345,8 +3337,8 @@ int nand_scan_tail(struct mtd_info *mtd) /* * Board driver should supply ecc.size and ecc.bytes values to * select how many bits are correctable; see nand_bch_init() - * for details. - * Otherwise, default to 4 bits for large page devices + * for details. Otherwise, default to 4 bits for large page + * devices. */ if (!chip->ecc.size && (mtd->oobsize >= 64)) { chip->ecc.size = 512; @@ -3383,7 +3375,7 @@ int nand_scan_tail(struct mtd_info *mtd) /* * The number of bytes available for a client to place data into - * the out of band area + * the out of band area. */ chip->ecc.layout->oobavail = 0; for (i = 0; chip->ecc.layout->oobfree[i].length @@ -3394,7 +3386,7 @@ int nand_scan_tail(struct mtd_info *mtd) /* * Set the number of read / write steps for one page depending on ECC - * mode + * mode. */ chip->ecc.steps = mtd->writesize / chip->ecc.size; if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { @@ -3403,10 +3395,7 @@ int nand_scan_tail(struct mtd_info *mtd) } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; - /* - * Allow subpage writes up to ecc.steps. Not possible for MLC - * FLASH. - */ + /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { switch (chip->ecc.steps) { @@ -3464,9 +3453,11 @@ int nand_scan_tail(struct mtd_info *mtd) } EXPORT_SYMBOL(nand_scan_tail); -/* is_module_text_address() isn't exported, and it's mostly a pointless +/* + * is_module_text_address() isn't exported, and it's mostly a pointless * test if this is a module _anyway_ -- they'd have to try _really_ hard - * to call us from in-kernel code if the core NAND support is modular. */ + * to call us from in-kernel code if the core NAND support is modular. + */ #ifdef MODULE #define caller_is_module() (1) #else @@ -3476,15 +3467,13 @@ EXPORT_SYMBOL(nand_scan_tail); /** * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller + * @mtd: MTD device structure + * @maxchips: number of chips to scan for * + * This fills out all the uninitialized function pointers with the defaults. + * The flash ID is read and the mtd/chip structures are filled with the + * appropriate values. The mtd->owner field must be set to the module of the + * caller. */ int nand_scan(struct mtd_info *mtd, int maxchips) { @@ -3506,8 +3495,8 @@ EXPORT_SYMBOL(nand_scan); /** * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd: MTD device structure -*/ + * @mtd: MTD device structure + */ void nand_release(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 9af703def4aa..ba401662835e 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -80,17 +80,15 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) /** * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @len: the length of buffer to search - * @paglen: the pagelength - * @td: search pattern descriptor + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. - * If the SCAN_EMPTY option is set then check, if all bytes except the - * pattern area contain 0xff - * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if + * all bytes except the pattern area contain 0xff. + */ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) { int i, end = 0; @@ -127,14 +125,13 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc /** * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. Same as check_pattern, but - * no optional empty check + * @buf: the buffer to search + * @td: search pattern descriptor * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. Same as check_pattern, but no optional empty + * check. + */ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) { int i; @@ -150,7 +147,7 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) /** * add_marker_len - compute the length of the marker in data area - * @td: BBT descriptor used for computation + * @td: BBT descriptor used for computation * * The length will be 0 if the markeris located in OOB area. */ @@ -169,15 +166,14 @@ static u32 add_marker_len(struct nand_bbt_descr *td) /** * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure - * @buf: temporary buffer - * @page: the starting page - * @num: the number of bbt descriptors to read - * @td: the bbt describtion table - * @offs: offset in the memory table + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: offset in the memory table * * Read the bad block table starting from page. - * */ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, struct nand_bbt_descr *td, int offs) @@ -229,11 +225,13 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, mtd->ecc_stats.bbtblocks++; continue; } - /* Leave it for now, if its matured we can move this - * message to MTD_DEBUG_LEVEL0 */ + /* + * Leave it for now, if it's matured we can + * move this message to MTD_DEBUG_LEVEL0. + */ printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - /* Factory marked bad or worn out ? */ + /* Factory marked bad or worn out? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); else @@ -249,15 +247,15 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, /** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @chip: read the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips; aplies only if + * NAND_BBT_PERCHIP option is set * - * Read the bad block table for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. -*/ + * Read the bad block table for all chips starting at a given page. We assume + * that the bbt bits are in consecutive order. + */ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) { struct nand_chip *this = mtd->priv; @@ -283,9 +281,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc return 0; } -/* - * BBT marker is in the first page, no OOB. - */ +/* BBT marker is in the first page, no OOB */ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, struct nand_bbt_descr *td) { @@ -299,9 +295,7 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return mtd->read(mtd, offs, len, &retlen, buf); } -/* - * Scan read raw data from flash - */ +/* Scan read raw data from flash */ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, size_t len) { @@ -344,9 +338,7 @@ static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return scan_read_raw_oob(mtd, buf, offs, len); } -/* - * Scan write data with oob to flash - */ +/* Scan write data with oob to flash */ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, uint8_t *buf, uint8_t *oob) { @@ -373,15 +365,14 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * - * Read the bad block table(s) for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror * -*/ + * Read the bad block table(s) for all chips starting at a given page. We + * assume that the bbt bits are in consecutive order. + */ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { @@ -407,9 +398,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, return 1; } -/* - * Scan a given block full - */ +/* Scan a given block full */ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, size_t readlen, int scanlen, int len) @@ -427,9 +416,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, return 0; } -/* - * Scan a given block partially - */ +/* Scan a given block partially */ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, int len) { @@ -444,9 +431,8 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, for (j = 0; j < len; j++) { /* - * Read the full oob until read_oob is fixed to - * handle single byte reads for 16 bit - * buswidth + * Read the full oob until read_oob is fixed to handle single + * byte reads for 16 bit buswidth. */ ret = mtd->read_oob(mtd, offs, &ops); if (ret) @@ -462,14 +448,14 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, /** * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * @chip: create the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips; applies only + * if NAND_BBT_PERCHIP option is set * - * Create a bad block table by scanning the device - * for the given good/bad block identify pattern + * Create a bad block table by scanning the device for the given good/bad block + * identify pattern. */ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) @@ -500,8 +486,10 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, } if (chip == -1) { - /* Note that numblocks is 2 * (real numblocks) here, see i+=2 - * below as it makes shifting and masking less painful */ + /* + * Note that numblocks is 2 * (real numblocks) here, see i+=2 + * below as it makes shifting and masking less painful + */ numblocks = mtd->size >> (this->bbt_erase_shift - 1); startblock = 0; from = 0; @@ -549,20 +537,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, /** * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table * - * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of - * the device downwards. The search starts always at the start of a - * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched - * for a bbt, which contains the bad block information of this chip. - * This is necessary to provide support for certain DOC devices. + * Read the bad block table by searching for a given ident pattern. Search is + * preformed either from the beginning up or from the end of the device + * downwards. The search starts always at the start of a block. If the option + * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains + * the bad block information of this chip. This is necessary to provide support + * for certain DOC devices. * - * The bbt ident pattern resides in the oob area of the first page - * in a block. + * The bbt ident pattern resides in the oob area of the first page in a block. */ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) { @@ -573,7 +559,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr int bbtblocks; int blocktopage = this->bbt_erase_shift - this->page_shift; - /* Search direction top -> down ? */ + /* Search direction top -> down? */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = (mtd->size >> this->bbt_erase_shift) - 1; dir = -1; @@ -582,7 +568,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr dir = 1; } - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; bbtblocks = this->chipsize >> this->bbt_erase_shift; @@ -631,13 +617,13 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror * - * Search and read the bad block table(s) -*/ + * Search and read the bad block table(s). + */ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ @@ -653,16 +639,14 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt /** * write_bbt - [GENERIC] (Re)write the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all * - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * @chipsel: selector for a specific chip, -1 for all - * - * (Re)write the bad block table - * -*/ + * (Re)write the bad block table. + */ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) @@ -685,10 +669,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (!rcode) rcode = 0xff; - /* Write bad block table per chip rather than per device ? */ + /* Write bad block table per chip rather than per device? */ if (td->options & NAND_BBT_PERCHIP) { numblocks = (int)(this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip ? */ + /* Full device write or specific chip? */ if (chipsel == -1) { nrchips = this->numchips; } else { @@ -702,8 +686,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /* Loop through the chips */ for (; chip < nrchips; chip++) { - - /* There was already a version of the table, reuse the page + /* + * There was already a version of the table, reuse the page * This applies for absolute placement too, as we have the * page nr. in td->pages. */ @@ -712,8 +696,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, goto write; } - /* Automatic placement of the bad block table */ - /* Search direction top -> down ? */ + /* + * Automatic placement of the bad block table. Search direction + * top -> down? + */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = numblocks * (chip + 1) - 1; dir = -1; @@ -764,7 +750,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, to = ((loff_t) page) << this->page_shift; - /* Must we save the block contents ? */ + /* Must we save the block contents? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); @@ -798,13 +784,13 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, } else if (td->options & NAND_BBT_NO_OOB) { ooboffs = 0; offs = td->len; - /* the version byte */ + /* The version byte */ if (td->options & NAND_BBT_VERSION) offs++; /* Calc length */ len = (size_t) (numblocks >> sft); len += offs; - /* Make it page aligned ! */ + /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len); @@ -813,7 +799,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, } else { /* Calc length */ len = (size_t) (numblocks >> sft); - /* Make it page aligned ! */ + /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len + @@ -827,13 +813,13 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (td->options & NAND_BBT_VERSION) buf[ooboffs + td->veroffs] = td->version[chip]; - /* walk through the memory table */ + /* Walk through the memory table */ for (i = 0; i < numblocks;) { uint8_t dat; dat = this->bbt[bbtoffs + (i >> 2)]; for (j = 0; j < 4; j++, i++) { int sftcnt = (i << (3 - sft)) & sftmsk; - /* Do not store the reserved bbt blocks ! */ + /* Do not store the reserved bbt blocks! */ buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); dat >>= 2; @@ -870,12 +856,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /** * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern * - * The function creates a memory based bbt by scanning the device - * for manufacturer / software marked good / bad blocks -*/ + * The function creates a memory based bbt by scanning the device for + * manufacturer / software marked good / bad blocks. + */ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; @@ -886,16 +872,15 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b /** * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern * - * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if necessary - * Creation is necessary if no bbt was found for the chip/device - * Update is necessary if one of the tables is missing or the - * version nr. of one table is less than the other -*/ + * The function checks the results of the previous call to read_bbt and creates + * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found + * for the chip/device. Update is necessary if one of the tables is missing or + * the version nr. of one table is less than the other. + */ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) { int i, chips, writeops, chipsel, res; @@ -904,7 +889,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc struct nand_bbt_descr *md = this->bbt_md; struct nand_bbt_descr *rd, *rd2; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) chips = this->numchips; else @@ -914,9 +899,9 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc writeops = 0; rd = NULL; rd2 = NULL; - /* Per chip or per device ? */ + /* Per chip or per device? */ chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; - /* Mirrored table available ? */ + /* Mirrored table available? */ if (md) { if (td->pages[i] == -1 && md->pages[i] == -1) { writeops = 0x03; @@ -965,7 +950,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc goto writecheck; } create: - /* Create the bad block table by scanning the device ? */ + /* Create the bad block table by scanning the device? */ if (!(td->options & NAND_BBT_CREATE)) continue; @@ -977,21 +962,21 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (md) md->version[i] = 1; writecheck: - /* read back first ? */ + /* Read back first? */ if (rd) read_abs_bbt(mtd, buf, rd, chipsel); - /* If they weren't versioned, read both. */ + /* If they weren't versioned, read both */ if (rd2) read_abs_bbt(mtd, buf, rd2, chipsel); - /* Write the bad block table to the device ? */ + /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) return res; } - /* Write the mirror bad block table to the device ? */ + /* Write the mirror bad block table to the device? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); if (res < 0) @@ -1003,20 +988,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /** * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure - * @td: bad block table descriptor + * @mtd: MTD device structure + * @td: bad block table descriptor * - * The bad block table regions are marked as "bad" to prevent - * accidental erasures / writes. The regions are identified by - * the mark 0x02. -*/ + * The bad block table regions are marked as "bad" to prevent accidental + * erasures / writes. The regions are identified by the mark 0x02. + */ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) { struct nand_chip *this = mtd->priv; int i, j, chips, block, nrblocks, update; uint8_t oldval, newval; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); @@ -1053,9 +1037,11 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) update = 1; block += 2; } - /* If we want reserved blocks to be recorded to flash, and some - new ones have been marked, then we need to update the stored - bbts. This should only happen once. */ + /* + * If we want reserved blocks to be recorded to flash, and some + * new ones have been marked, then we need to update the stored + * bbts. This should only happen once. + */ if (update && td->reserved_block_code) nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); } @@ -1063,8 +1049,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure - * @bd: the table to verify + * @mtd: MTD device structure + * @bd: the table to verify * * This functions performs a few sanity checks on the bad block description * table. @@ -1111,18 +1097,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern * - * The function checks, if a bad block table(s) is/are already - * available. If not it scans the device for manufacturer - * marked good / bad blocks and writes the bad block table(s) to - * the selected place. + * The function checks, if a bad block table(s) is/are already available. If + * not it scans the device for manufacturer marked good / bad blocks and writes + * the bad block table(s) to the selected place. * - * The bad block table memory is allocated here. It must be freed - * by calling the nand_free_bbt function. - * -*/ + * The bad block table memory is allocated here. It must be freed by calling + * the nand_free_bbt function. + */ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; @@ -1132,15 +1116,19 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) struct nand_bbt_descr *md = this->bbt_md; len = mtd->size >> (this->bbt_erase_shift + 2); - /* Allocate memory (2bit per block) and clear the memory bad block table */ + /* + * Allocate memory (2bit per block) and clear the memory bad block + * table. + */ this->bbt = kzalloc(len, GFP_KERNEL); if (!this->bbt) { printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); return -ENOMEM; } - /* If no primary table decriptor is given, scan the device - * to build a memory based bad block table + /* + * If no primary table decriptor is given, scan the device to build a + * memory based bad block table. */ if (!td) { if ((res = nand_memory_bbt(mtd, bd))) { @@ -1164,7 +1152,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) return -ENOMEM; } - /* Is the bbt at a given page ? */ + /* Is the bbt at a given page? */ if (td->options & NAND_BBT_ABSPAGE) { res = read_abs_bbts(mtd, buf, td, md); } else { @@ -1186,11 +1174,11 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_update_bbt - [NAND Interface] update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block + * @mtd: MTD device structure + * @offs: the offset of the newly marked block * - * The function updates the bad block table(s) -*/ + * The function updates the bad block table(s). + */ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) { struct nand_chip *this = mtd->priv; @@ -1214,7 +1202,7 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) writeops = md != NULL ? 0x03 : 0x01; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chip = (int)(offs >> this->chip_shift); chipsel = chip; @@ -1227,13 +1215,13 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) if (md) md->version[chip]++; - /* Write the bad block table to the device ? */ + /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) goto out; } - /* Write the mirror bad block table to the device ? */ + /* Write the mirror bad block table to the device? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); } @@ -1243,8 +1231,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) return res; } -/* Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks. */ +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; @@ -1256,8 +1246,7 @@ static struct nand_bbt_descr agand_flashbased = { .pattern = scan_agand_pattern }; -/* Generic flash bbt decriptors -*/ +/* Generic flash bbt decriptors */ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; @@ -1303,13 +1292,12 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { /** * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure - * @this: NAND chip to create descriptor for + * @this: NAND chip to create descriptor for * * This function allocates and initializes a nand_bbt_descr for BBM detection * based on the properties of "this". The new descriptor is stored in * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when * passed to this function. - * */ static int nand_create_default_bbt_descr(struct nand_chip *this) { @@ -1334,22 +1322,20 @@ static int nand_create_default_bbt_descr(struct nand_chip *this) /** * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd: MTD device structure - * - * This function selects the default bad block table - * support for the device and calls the nand_scan_bbt function + * @mtd: MTD device structure * -*/ + * This function selects the default bad block table support for the device and + * calls the nand_scan_bbt function. + */ int nand_default_bbt(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - /* Default for AG-AND. We must use a flash based - * bad block table as the devices have factory marked - * _good_ blocks. Erasing those blocks leads to loss - * of the good / bad information, so we _must_ store - * this information in a good / bad table during - * startup + /* + * Default for AG-AND. We must use a flash based bad block table as the + * devices have factory marked _good_ blocks. Erasing those blocks + * leads to loss of the good / bad information, so we _must_ store this + * information in a good / bad table during startup. */ if (this->options & NAND_IS_AND) { /* Use the default pattern descriptors */ @@ -1361,7 +1347,7 @@ int nand_default_bbt(struct mtd_info *mtd) return nand_scan_bbt(mtd, &agand_flashbased); } - /* Is a flash based bad block table requested ? */ + /* Is a flash based bad block table requested? */ if (this->bbt_options & NAND_BBT_USE_FLASH) { /* Use the default pattern descriptors */ if (!this->bbt_td) { @@ -1386,11 +1372,10 @@ int nand_default_bbt(struct mtd_info *mtd) /** * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure - * @offs: offset in the device - * @allowbbt: allow access to bad block table region - * -*/ + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + */ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) { struct nand_chip *this = mtd->priv; From bf5140817b2d65faac9b32fc9057a097044ac35b Mon Sep 17 00:00:00 2001 From: Peter Wippich Date: Mon, 6 Jun 2011 15:50:58 +0200 Subject: [PATCH 0202/1596] mtd: mtdchar: add missing initializer on raw write On writes in MODE_RAW the mtd_oob_ops struct is not sufficiently initialized which may cause nandwrite to fail. With this patch it is possible to write raw nand/oob data without additional ECC (either for testing or when some sectors need different oob layout e.g. bootloader) like nandwrite -n -r -o /dev/mtd0 Signed-off-by: Peter Wippich Cc: stable@kernel.org Tested-by: Ricard Wanderlof Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index f1af2228a1b1..49e20a497084 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -320,6 +320,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count ops.mode = MTD_OOB_RAW; ops.datbuf = kbuf; ops.oobbuf = NULL; + ops.ooboffs = 0; ops.len = len; ret = mtd->write_oob(mtd, *ppos, &ops); From 1a31368bf92ef2a7da3ba379672c405bd2751df9 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 6 Jun 2011 18:04:14 +0400 Subject: [PATCH 0203/1596] mtd: add a flags for partitions which should just leave smth. after them Add support for MTDPART_OFS_RETAIN: such partitions start at the current offset, take as much space as possible, but rain part->size bytes after the end of the partitions for other parts. Primarily this is intended for ts72xx arm platforms cleanup. Artem: tweaked the patch a bit Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdpart.c | 13 +++++++++++++ include/linux/mtd/partitions.h | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 3477e16be1c8..b73720502433 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -479,6 +479,19 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, (unsigned long long)cur_offset, (unsigned long long)slave->offset); } } + if (slave->offset == MTDPART_OFS_RETAIN) { + slave->offset = cur_offset; + if (master->size - slave->offset >= slave->mtd.size) { + slave->mtd.size = master->size - slave->offset + - slave->mtd.size; + } else { + printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n", + part->name, master->size - slave->offset, + slave->mtd.size); + /* register to preserve ordering */ + goto out_register; + } + } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 08c9c7b8b8e2..1431cf2609ed 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -24,7 +24,9 @@ * will extend to the end of the master MTD device. * offset: absolute starting position within the master MTD device; if * defined as MTDPART_OFS_APPEND, the partition will start where the - * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. + * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block; + * if MTDPART_OFS_RETAIN, consume as much as possible, leaving size + * after the end of partition. * mask_flags: contains flags that have to be masked (removed) from the * master MTD flag set for the corresponding MTD partition. * For example, to force a read-only partition, simply adding @@ -42,6 +44,7 @@ struct mtd_partition { struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */ }; +#define MTDPART_OFS_RETAIN (-3) #define MTDPART_OFS_NXTBLK (-2) #define MTDPART_OFS_APPEND (-1) #define MTDPART_SIZ_FULL (0) From 78dd9e3500873edd6005a41f8ba178eacbff64c5 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 6 Jun 2011 18:04:15 +0400 Subject: [PATCH 0204/1596] ts72xx: use MTDPART_OFS_RETAIN for mtd partitioning Instead of specifying a callback for dynamic partitioning, use MTDPART_OFS_RETAIN for reserving a place near the end of flash for RedBoot. Signed-off-by: Dmitry Eremin-Solenikov Cc: Hartley Sweeten Cc: Ryan Mallon Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Artem Bityutskiy --- arch/arm/mach-ep93xx/ts72xx.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index c2d2cf40ead9..dea42e262151 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -116,8 +116,9 @@ static struct mtd_partition ts72xx_nand_parts[] = { .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { .name = "Linux", - .offset = MTDPART_OFS_APPEND, - .size = 0, /* filled in later */ + .offset = MTDPART_OFS_RETAIN, + .size = TS72XX_REDBOOT_PART_SIZE, + /* leave so much for last partition */ }, { .name = "RedBoot", .offset = MTDPART_OFS_APPEND, @@ -126,28 +127,14 @@ static struct mtd_partition ts72xx_nand_parts[] = { }, }; -static void ts72xx_nand_set_parts(uint64_t size, - struct platform_nand_chip *chip) -{ - /* Factory TS-72xx boards only come with 32MiB or 128MiB NAND options */ - if (size == SZ_32M || size == SZ_128M) { - /* Set the "Linux" partition size */ - ts72xx_nand_parts[1].size = size - TS72XX_REDBOOT_PART_SIZE; - - chip->partitions = ts72xx_nand_parts; - chip->nr_partitions = ARRAY_SIZE(ts72xx_nand_parts); - } else { - pr_warning("Unknown nand disk size:%lluMiB\n", size >> 20); - } -} - static struct platform_nand_data ts72xx_nand_data = { .chip = { .nr_chips = 1, .chip_offset = 0, .chip_delay = 15, .part_probe_types = ts72xx_nand_part_probes, - .set_parts = ts72xx_nand_set_parts, + .partitions = ts72xx_nand_parts, + .nr_partitions = ARRAY_SIZE(ts72xx_nand_parts), }, .ctrl = { .cmd_ctrl = ts72xx_nand_hwcontrol, From 0dc8626a17ab8dea9f1e34c7a5d667f5331b0ddc Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 6 Jun 2011 18:04:16 +0400 Subject: [PATCH 0205/1596] mtd: plat-nand: drop unused fields from platform_nand_data Drop now unused set_parts from struct platform_nand_data. Also, while we are at it, drop long unused priv field from platform_nand_data. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/plat_nand.c | 2 -- include/linux/mtd/nand.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index ccdb16ec8143..746a723b4933 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -109,8 +109,6 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) return 0; } } - if (pdata->chip.set_parts) - pdata->chip.set_parts(data->mtd.size, &pdata->chip); if (pdata->chip.partitions) { data->parts = pdata->chip.partitions; err = mtd_device_register(&data->mtd, data->parts, diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 4a43ffc535c9..0f239e714219 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -619,8 +619,6 @@ struct platform_nand_chip { unsigned int options; unsigned int bbt_options; const char **part_probe_types; - void (*set_parts)(uint64_t size, struct platform_nand_chip *chip); - void *priv; }; /* Keep gcc happy */ From bc27ede371b0931086e9cef72e30a58fdedc4709 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Mon, 6 Jun 2011 17:11:34 +0100 Subject: [PATCH 0206/1596] mtd: denali: detect the number of banks before resetting NAND Commit c89eeda810f0ec4f0eee0206ebb79e476df9f83e (mtd: denali: detect the number of banks) introduced runtime detection of the number of banks. However, denali_nand_reset() uses uses denanli_nand_info::max_banks so we need to detect the maximum number of banks before doing the reset. Signed-off-by: Jamie Iles Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/denali.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index eebdfb5148e6..3984d488f9ab 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1346,6 +1346,7 @@ static void denali_hw_init(struct denali_nand_info *denali) * */ denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); + detect_max_banks(denali); denali_nand_reset(denali); iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, @@ -1356,7 +1357,6 @@ static void denali_hw_init(struct denali_nand_info *denali) /* Should set value for these registers when init */ iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); iowrite32(1, denali->flash_reg + ECC_ENABLE); - detect_max_banks(denali); denali_nand_timing_set(denali); denali_irq_init(denali); } From 0fab028b77d714ad302404b23306cf7adb885223 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Tue, 7 Jun 2011 03:01:06 -0700 Subject: [PATCH 0207/1596] mtd: pxa3xx_nand: fix nand detection issue When keep_config is set, the detection would goes different routine. That the driver would read out the setting which is set previously by bootloader. While most bootloader keep the irq mask as off, and current driver need all irq default open, keep_config behavior would lead to no irq at all. Signed-off-by: Lei Wen Tested-by: Daniel Mack Cc: stable@kernel.org [2.6.38+] Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/pxa3xx_nand.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index c7da3c8be9d6..9fde1399af91 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -813,7 +813,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; /* set info fields needed to read id */ info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; - info->reg_ndcr = ndcr; + info->reg_ndcr = ndcr & ~NDCR_INT_MASK; info->cmdset = &default_cmdset; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); @@ -882,7 +882,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) struct pxa3xx_nand_info *info = mtd->priv; struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; - struct nand_flash_dev pxa3xx_flash_ids[2] = { {NULL,}, {NULL,} }; + struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; const struct pxa3xx_nand_flash *f = NULL; struct nand_chip *chip = mtd->priv; uint32_t id = -1; @@ -942,8 +942,10 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block; if (f->flash_width == 16) pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16; + pxa3xx_flash_ids[1].name = NULL; + def = pxa3xx_flash_ids; KEEP_CONFIG: - if (nand_scan_ident(mtd, 1, pxa3xx_flash_ids)) + if (nand_scan_ident(mtd, 1, def)) return -ENODEV; /* calculate addressing information */ info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; @@ -954,9 +956,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) info->row_addr_cycles = 2; mtd->name = mtd_names[0]; chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = f->page_size; + chip->ecc.size = info->page_size; - chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0; + chip->options = (info->reg_ndcr & NDCR_DWIDTH_M) ? NAND_BUSWIDTH_16 : 0; chip->options |= NAND_NO_AUTOINCR; chip->options |= NAND_NO_READRDY; From 543e32d5ff165d0d68deedb0e3557478c7c36a4a Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 7 Jun 2011 03:01:07 -0700 Subject: [PATCH 0208/1596] mtd: pxa3xx_nand: Fix blank page ECC mismatch This bug was introduced in f8155a40 ("mtd: pxa3xx_nand: rework irq logic") and causes the PXA3xx NAND controller fail to operate with NAND flash that has empty pages. According to the comment in this block, the hardware controller will report a double-bit error for empty pages, which can and must be ignored. This patch restores the original behaviour of the driver. Signed-off-by: Daniel Mack Acked-by: Lei Wen Cc: Haojian Zhuang Cc: David Woodhouse Cc: stable@kernel.org [2.6.38+] Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/pxa3xx_nand.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 9fde1399af91..5c3af2f72a62 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -685,6 +685,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, * OOB, ignore such double bit errors */ if (is_buf_blank(buf, mtd->writesize)) + info->retcode = ERR_NONE; + else mtd->ecc_stats.failed++; } From ad274cecdbce18d13075bde3aabe5882802056de Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 8 Jun 2011 11:42:27 +0300 Subject: [PATCH 0209/1596] mtd: document parse_mtd_partitions Add a kerneldoc comment for the 'parse_mtd_partitions()' function - its behavior has changed recently so it is good idea to have it documented. Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdpart.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index b73720502433..2b71ccb00d39 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -725,8 +725,30 @@ int deregister_mtd_parser(struct mtd_part_parser *p) } EXPORT_SYMBOL_GPL(deregister_mtd_parser); +/* + * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you + * are changing this array! + */ static const char *default_mtd_part_types[] = {"cmdlinepart", NULL}; +/** + * parse_mtd_partitions - parse MTD partitions + * @master: the master partition (describes whole MTD device) + * @types: names of partition parsers to try or %NULL + * @pparts: array of partitions found is returned here + * @origin: MTD device start address (use %0 if unsure) + * + * This function tries to find partition on MTD device @master. It uses MTD + * partition parsers, specified in @types. However, if @types is %NULL, then + * the default list of parsers is used. The default list contains only the + * "cmdlinepart" parser ATM. + * + * This function may return: + * o a negative error code in case of failure + * o zero if no partitions were found + * o a positive number of found partitions, in which case on exit @pparts will + * point to an array containing this number of &struct mtd_info objects. + */ int parse_mtd_partitions(struct mtd_info *master, const char **types, struct mtd_partition **pparts, unsigned long origin) { From 96166056076af59d40e5b5aec5b09611c74cc911 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 7 Jun 2011 22:55:21 +0800 Subject: [PATCH 0210/1596] mtd: ndfc: fix a memory leak in ndfc_remove Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/ndfc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index cb66fd79f1fa..70c04ffa573c 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -283,6 +283,7 @@ static int __devexit ndfc_remove(struct platform_device *ofdev) struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); nand_release(&ndfc->mtd); + kfree(ndfc->mtd.name); return 0; } From 0870066d7e6c85bbe37741137e4c4731501a98e0 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 7 Jun 2011 16:01:54 -0700 Subject: [PATCH 0211/1596] mtd: remove printk's for [kv][mz]alloc failures When a memory allocation fails, the kernel will print out a backtrace automatically. These print statements are unnecessary. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/cmdlinepart.c | 3 --- drivers/mtd/inftlcore.c | 4 +--- drivers/mtd/nand/nand_bbt.c | 13 +++---------- drivers/mtd/nand/rtc_from4.c | 1 - drivers/mtd/nftlcore.c | 4 +--- drivers/mtd/onenand/onenand_bbt.c | 4 +--- drivers/mtd/ssfdc.c | 10 ++-------- 7 files changed, 8 insertions(+), 31 deletions(-) diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index e790f38893b0..be0c121f2f1b 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -188,10 +188,7 @@ static struct mtd_partition * newpart(char *s, extra_mem_size; parts = kzalloc(alloc_size, GFP_KERNEL); if (!parts) - { - printk(KERN_ERR ERRP "out of memory\n"); return NULL; - } extra_mem = (unsigned char *)(parts + *num_parts); } /* enter this partition (offset will be calculated later if it is zero at this point) */ diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index d7592e67d048..c9a31e6faab2 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -67,10 +67,8 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) inftl = kzalloc(sizeof(*inftl), GFP_KERNEL); - if (!inftl) { - printk(KERN_WARNING "INFTL: Out of memory for data structures\n"); + if (!inftl) return; - } inftl->mbd.mtd = mtd; inftl->mbd.devnum = -1; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ba401662835e..8875d6db2455 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1121,10 +1121,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) * table. */ this->bbt = kzalloc(len, GFP_KERNEL); - if (!this->bbt) { - printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); + if (!this->bbt) return -ENOMEM; - } /* * If no primary table decriptor is given, scan the device to build a @@ -1146,7 +1144,6 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) len += (len >> this->page_shift) * mtd->oobsize; buf = vmalloc(len); if (!buf) { - printk(KERN_ERR "nand_bbt: Out of memory\n"); kfree(this->bbt); this->bbt = NULL; return -ENOMEM; @@ -1195,10 +1192,8 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; buf = kmalloc(len, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "nand_update_bbt: Out of memory\n"); + if (!buf) return -ENOMEM; - } writeops = md != NULL ? 0x03 : 0x01; @@ -1307,10 +1302,8 @@ static int nand_create_default_bbt_descr(struct nand_chip *this) return -EINVAL; } bd = kzalloc(sizeof(*bd), GFP_KERNEL); - if (!bd) { - printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); + if (!bd) return -ENOMEM; - } bd->options = this->bbt_options; bd->offs = this->badblockpos; bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index c9f9127ff770..a07da2a3beee 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -444,7 +444,6 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, len = mtd->writesize; buf = kmalloc(len, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n"); er_stat = 1; goto out; } diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index b155666acfbe..f3b3239746c8 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -67,10 +67,8 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL); - if (!nftl) { - printk(KERN_WARNING "NFTL: out of memory for data structures\n"); + if (!nftl) return; - } nftl->mbd.mtd = mtd; nftl->mbd.devnum = -1; diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index fc2c16a0fd1c..09a7d1fb511d 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -188,10 +188,8 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) len = this->chipsize >> (this->erase_shift + 2); /* Allocate memory (2bit per block) and clear the memory bad block table */ bbm->bbt = kzalloc(len, GFP_KERNEL); - if (!bbm->bbt) { - printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); + if (!bbm->bbt) return -ENOMEM; - } /* Set the bad block position */ bbm->badblockpos = ONENAND_BADBLOCK_POS; diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 5cd189793332..00d1405af50b 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -304,11 +304,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; ssfdc = kzalloc(sizeof(struct ssfdcr_record), GFP_KERNEL); - if (!ssfdc) { - printk(KERN_WARNING - "SSFDC_RO: out of memory for data structures\n"); + if (!ssfdc) return; - } ssfdc->mbd.mtd = mtd; ssfdc->mbd.devnum = -1; @@ -342,11 +339,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) /* Allocate logical block map */ ssfdc->logic_block_map = kmalloc(sizeof(ssfdc->logic_block_map[0]) * ssfdc->map_len, GFP_KERNEL); - if (!ssfdc->logic_block_map) { - printk(KERN_WARNING - "SSFDC_RO: out of memory for data structures\n"); + if (!ssfdc->logic_block_map) goto out_err; - } memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) * ssfdc->map_len); From 3b36013cf9cc1a1da93ad6bb8f6d3b0221f67e42 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 8 Jun 2011 21:01:37 +0800 Subject: [PATCH 0212/1596] mtd: davinci_nand: remove redundant mtd_device_unregister mtd_device_unregister is done in nand_release(), thus no need to call it in nand_davinci_remove(). Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/davinci_nand.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 0c582ed98e43..70c92a527f6b 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -811,9 +811,6 @@ static int __init nand_davinci_probe(struct platform_device *pdev) static int __exit nand_davinci_remove(struct platform_device *pdev) { struct davinci_nand_info *info = platform_get_drvdata(pdev); - int status; - - status = mtd_device_unregister(&info->mtd); spin_lock_irq(&davinci_nand_lock); if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME) From 3761a6ddacc83e5a6b4482d98fbf212805381486 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 8 Jun 2011 19:59:49 +0400 Subject: [PATCH 0213/1596] mtd: lart: cleanup: drop HAVE_PARTITIONS Consolidate knowledge about partitions in drivers/mtd/devices/lart.c. Drop all HAVE_PARTITIONS conditionals. Always use partitioning. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/lart.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 772a0ff89e0f..3a11ea628e58 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -34,9 +34,6 @@ /* debugging */ //#define LART_DEBUG -/* partition support */ -#define HAVE_PARTITIONS - #include #include #include @@ -44,9 +41,7 @@ #include #include #include -#ifdef HAVE_PARTITIONS #include -#endif #ifndef CONFIG_SA1100_LART #error This is for LART architecture only @@ -598,7 +593,6 @@ static struct mtd_erase_region_info erase_regions[] = { } }; -#ifdef HAVE_PARTITIONS static struct mtd_partition lart_partitions[] = { /* blob */ { @@ -619,7 +613,7 @@ static struct mtd_partition lart_partitions[] = { .size = INITRD_LEN, /* MTDPART_SIZ_FULL */ } }; -#endif +#define NUM_PARTITIONS ARRAY_SIZE(lart_partitions) static int __init lart_flash_init (void) { @@ -668,7 +662,6 @@ static int __init lart_flash_init (void) result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024, result,mtd.eraseregions[result].numblocks); -#ifdef HAVE_PARTITIONS printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions)); for (result = 0; result < ARRAY_SIZE(lart_partitions); result++) @@ -681,25 +674,16 @@ static int __init lart_flash_init (void) result,lart_partitions[result].offset, result,lart_partitions[result].size,lart_partitions[result].size / 1024); #endif -#endif -#ifndef HAVE_PARTITIONS - result = mtd_device_register(&mtd, NULL, 0); -#else result = mtd_device_register(&mtd, lart_partitions, ARRAY_SIZE(lart_partitions)); -#endif return (result); } static void __exit lart_flash_exit (void) { -#ifndef HAVE_PARTITIONS - mtd_device_unregister(&mtd); -#else mtd_device_unregister(&mtd); -#endif } module_init (lart_flash_init); From 1c4c215cbdcbfd08183d82b2953591cd00564422 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 25 Mar 2011 22:26:25 +0300 Subject: [PATCH 0214/1596] mtd: add new API for handling MTD registration Lots (nearly all) mtd drivers contain nearly the similar code that calls parse_mtd_partitions, provides some platform-default values, if parsing fails, and registers mtd device. This is an aim to provide single implementation of this scenario: mtd_device_parse_register() which will handle all this parsing and defaults. Artem: amended comments Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdcore.c | 58 +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/mtd.h | 5 ++++ 2 files changed, 63 insertions(+) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c510aff289a8..13267477e4e9 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -451,6 +451,64 @@ int mtd_device_register(struct mtd_info *master, } EXPORT_SYMBOL_GPL(mtd_device_register); +/** + * mtd_device_parse_register - parse partitions and register an MTD device. + * + * @mtd: the MTD device to register + * @types: the list of MTD partition probes to try, see + * 'parse_mtd_partitions()' for more information + * @origin: start address of MTD device, %0 unless you are sure you need this. + * @parts: fallback partition information to register, if parsing fails; + * only valid if %nr_parts > %0 + * @nr_parts: the number of partitions in parts, if zero then the full + * MTD device is registered if no partition info is found + * + * This function aggregates MTD partitions parsing (done by + * 'parse_mtd_partitions()') and MTD device and partitions registering. It + * basically follows the most common pattern found in many MTD drivers: + * + * * It first tries to probe partitions on MTD device @mtd using parsers + * specified in @types (if @types is %NULL, then the default list of parsers + * is used, see 'parse_mtd_partitions()' for more information). If none are + * found this functions tries to fallback to information specified in + * @parts/@nr_parts. + * * If any parititioning info was found, this function registers the found + * partitions. + * * If no partitions were found this function just registers the MTD device + * @mtd and exits. + * + * Returns zero in case of success and a negative error code in case of failure. + */ +int mtd_device_parse_register(struct mtd_info *mtd, const char **types, + unsigned long origin, + const struct mtd_partition *parts, + int nr_parts) +{ + int err; + struct mtd_partition *real_parts; + + err = parse_mtd_partitions(mtd, types, &real_parts, origin); + if (err <= 0 && nr_parts) { + real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, + GFP_KERNEL); + err = nr_parts; + if (!parts) + err = -ENOMEM; + } + + if (err > 0) { + err = add_mtd_partitions(mtd, real_parts, err); + kfree(real_parts); + } else if (err == 0) { + err = add_mtd_device(mtd); + if (err == 1) + err = -ENODEV; + } + + return err; +} +EXPORT_SYMBOL_GPL(mtd_device_parse_register); + /** * mtd_device_unregister - unregister an existing MTD device. * diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 2541fb848daa..d28a241e7b55 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -327,6 +327,11 @@ struct mtd_partition; extern int mtd_device_register(struct mtd_info *master, const struct mtd_partition *parts, int nr_parts); +extern int mtd_device_parse_register(struct mtd_info *mtd, + const char **part_probe_types, + unsigned long origin, + const struct mtd_partition *defparts, + int defnr_parts); extern int mtd_device_unregister(struct mtd_info *master); extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); extern int __get_mtd_device(struct mtd_info *mtd); From 81939afce261694f8e91a71e2cc7c817c13c57fd Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:23 +0400 Subject: [PATCH 0215/1596] mtd: sst25l.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/sst25l.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 52eb92edde93..44a8b408ed7b 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -52,8 +52,6 @@ struct sst25l_flash { struct spi_device *spi; struct mutex lock; struct mtd_info mtd; - - int partitioned; }; struct flash_info { @@ -381,8 +379,6 @@ static int __devinit sst25l_probe(struct spi_device *spi) struct sst25l_flash *flash; struct flash_platform_data *data; int ret, i; - struct mtd_partition *parts = NULL; - int nr_parts = 0; flash_info = sst25l_match_device(spi); if (!flash_info) @@ -423,31 +419,10 @@ static int __devinit sst25l_probe(struct spi_device *spi) flash->mtd.numeraseregions); - nr_parts = parse_mtd_partitions(&flash->mtd, NULL, &parts, 0); - - if (nr_parts <= 0 && data && data->parts) { - parts = data->parts; - nr_parts = data->nr_parts; - } - - if (nr_parts > 0) { - for (i = 0; i < nr_parts; i++) { - DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " - "{.name = %s, .offset = 0x%llx, " - ".size = 0x%llx (%lldKiB) }\n", - i, parts[i].name, - (long long)parts[i].offset, - (long long)parts[i].size, - (long long)(parts[i].size >> 10)); - } - - flash->partitioned = 1; - return mtd_device_register(&flash->mtd, parts, - nr_parts); - } - - ret = mtd_device_register(&flash->mtd, NULL, 0); - if (ret == 1) { + ret = mtd_device_parse_register(&flash->mtd, NULL, 0, + data ? data->parts : NULL, + data ? data->nr_parts : 0); + if (ret) { kfree(flash); dev_set_drvdata(&spi->dev, NULL); return -ENODEV; From cd3aafd0bd3ad383fd43196bc8dcac2edfec95c2 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:30 +0400 Subject: [PATCH 0216/1596] mtd: bfin-async-flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/bfin-async-flash.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 67815eed2f00..6d6b2b5674ee 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -41,7 +41,6 @@ struct async_state { uint32_t flash_ambctl0, flash_ambctl1; uint32_t save_ambctl0, save_ambctl1; unsigned long irq_flags; - struct mtd_partition *parts; }; static void switch_to_flash(struct async_state *state) @@ -165,18 +164,8 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev) return -ENXIO; } - ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0); - if (ret > 0) { - pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n"); - mtd_device_register(state->mtd, pdata->parts, ret); - state->parts = pdata->parts; - } else if (pdata->nr_parts) { - pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n"); - mtd_device_register(state->mtd, pdata->parts, pdata->nr_parts); - } else { - pr_devinit(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n"); - mtd_device_register(state->mtd, NULL, 0); - } + mtd_device_parse_register(state->mtd, part_probe_types, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, state); @@ -188,7 +177,6 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev) struct async_state *state = platform_get_drvdata(pdev); gpio_free(state->enet_flash_pin); mtd_device_unregister(state->mtd); - kfree(state->parts); map_destroy(state->mtd); kfree(state); return 0; From 3d0e9db409909a0259fa005fee81a7c639bd645a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:35 +0400 Subject: [PATCH 0217/1596] mtd: dc21285.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/dc21285.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index 7a9e1989c977..f43b365b848c 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -145,14 +145,10 @@ static struct map_info dc21285_map = { /* Partition stuff */ -static struct mtd_partition *dc21285_parts; static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int __init init_dc21285(void) { - - int nrparts; - /* Determine bankwidth */ switch (*CSR_SA110_CNTL & (3<<14)) { case SA110_CNTL_ROMWIDTH_8: @@ -200,8 +196,7 @@ static int __init init_dc21285(void) dc21285_mtd->owner = THIS_MODULE; - nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); - mtd_device_register(dc21285_mtd, dc21285_parts, nrparts); + mtd_device_parse_register(dc21285_mtd, probes, 0, NULL, 0); if(machine_is_ebsa285()) { /* @@ -224,8 +219,6 @@ static int __init init_dc21285(void) static void __exit cleanup_dc21285(void) { mtd_device_unregister(dc21285_mtd); - if (dc21285_parts) - kfree(dc21285_parts); map_destroy(dc21285_mtd); iounmap(dc21285_map.virt); } From 534e4928ad672a319c29b9f0c0593ad16766de53 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:41 +0400 Subject: [PATCH 0218/1596] mtd: gpio-addr-flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/gpio-addr-flash.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 7568c5f8b8ae..1ec66f031c51 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -187,7 +187,6 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; */ static int __devinit gpio_flash_probe(struct platform_device *pdev) { - int nr_parts; size_t i, arr_size; struct physmap_flash_data *pdata; struct resource *memory; @@ -252,20 +251,9 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev) return -ENXIO; } - nr_parts = parse_mtd_partitions(state->mtd, part_probe_types, - &pdata->parts, 0); - if (nr_parts > 0) { - pr_devinit(KERN_NOTICE PFX "Using commandline partition definition\n"); - kfree(pdata->parts); - } else if (pdata->nr_parts) { - pr_devinit(KERN_NOTICE PFX "Using board partition definition\n"); - nr_parts = pdata->nr_parts; - } else { - pr_devinit(KERN_NOTICE PFX "no partition info available, registering whole flash at once\n"); - nr_parts = 0; - } - mtd_device_register(state->mtd, pdata->parts, nr_parts); + mtd_device_parse_register(state->mtd, part_probe_types, 0, + pdata->parts, pdata->nr_parts); return 0; } From 8db2a08ee469c1fcad5354c1144a673d88434424 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:42 +0400 Subject: [PATCH 0219/1596] mtd: h720x-flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/h720x-flash.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index f331a2c94271..49c14187fc66 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -58,16 +58,11 @@ static struct mtd_partition h720x_partitions[] = { #define NUM_PARTITIONS ARRAY_SIZE(h720x_partitions) -static int nr_mtd_parts; -static struct mtd_partition *mtd_parts; /* * Initialize FLASH support */ static int __init h720x_mtd_init(void) { - - char *part_type = NULL; - h720x_map.virt = ioremap(h720x_map.phys, h720x_map.size); if (!h720x_map.virt) { @@ -90,16 +85,8 @@ static int __init h720x_mtd_init(void) if (mymtd) { mymtd->owner = THIS_MODULE; - nr_mtd_parts = parse_mtd_partitions(mymtd, NULL, &mtd_parts, 0); - if (nr_mtd_parts > 0) - part_type = "command line"; - if (nr_mtd_parts <= 0) { - mtd_parts = h720x_partitions; - nr_mtd_parts = NUM_PARTITIONS; - part_type = "builtin"; - } - printk(KERN_INFO "Using %s partition table\n", part_type); - mtd_device_register(mymtd, mtd_parts, nr_mtd_parts); + mtd_device_parse_register(mymtd, NULL, 0, + h720x_partitions, NUM_PARTITIONS); return 0; } @@ -118,10 +105,6 @@ static void __exit h720x_mtd_cleanup(void) map_destroy(mymtd); } - /* Free partition info, if commandline partition was used */ - if (mtd_parts && (mtd_parts != h720x_partitions)) - kfree (mtd_parts); - if (h720x_map.virt) { iounmap((void *)h720x_map.virt); h720x_map.virt = 0; From 5003403b87283a5e304e0248918ef678dbd24d59 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:44 +0400 Subject: [PATCH 0220/1596] mtd: impa7.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Artem: rename static_partitions to make lines shorter and align the way this driver prefers. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/impa7.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 2d45a489622e..f47aedb24366 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -49,7 +49,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = { /* * MTD partitioning stuff */ -static struct mtd_partition static_partitions[] = +static struct mtd_partition partitions[] = { { .name = "FileSystem", @@ -58,15 +58,10 @@ static struct mtd_partition static_partitions[] = }, }; -static int mtd_parts_nb[NUM_FLASHBANKS]; -static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; - - static int __init init_impa7(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; - const char *part_type = 0; int i; static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = { { WINDOW_ADDR0, WINDOW_SIZE0 }, @@ -96,23 +91,9 @@ static int __init init_impa7(void) if (impa7_mtd[i]) { impa7_mtd[i]->owner = THIS_MODULE; devicesfound++; - mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], - NULL, - &mtd_parts[i], - 0); - if (mtd_parts_nb[i] > 0) { - part_type = "command line"; - } else { - mtd_parts[i] = static_partitions; - mtd_parts_nb[i] = ARRAY_SIZE(static_partitions); - part_type = "static"; - } - - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", - part_type); - mtd_device_register(impa7_mtd[i], - mtd_parts[i], mtd_parts_nb[i]); + mtd_device_parse_register(impa7_mtd[i], NULL, 0, + partitions, + ARRAY_SIZE(partitions)); } else iounmap((void *)impa7_map[i].virt); From ba6bead4469bec8a66f1764106f23890b2a267e2 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:45 +0400 Subject: [PATCH 0221/1596] mtd: intel_vr_nor.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/intel_vr_nor.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index fd612c7ec1f6..08c239604ee4 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -44,7 +44,6 @@ struct vr_nor_mtd { void __iomem *csr_base; struct map_info map; struct mtd_info *info; - int nr_parts; struct pci_dev *dev; }; @@ -71,12 +70,9 @@ static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p) static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p) { - struct mtd_partition *parts; - /* register the flash bank */ /* partition the flash bank */ - p->nr_parts = parse_mtd_partitions(p->info, NULL, &parts, 0); - return mtd_device_register(p->info, parts, p->nr_parts); + return mtd_device_parse_register(p->info, NULL, 0, NULL, 0); } static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) From 200b8777ce270b491affb2bd81192f78f2d46213 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:46 +0400 Subject: [PATCH 0222/1596] mtd: ixp2000.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/ixp2000.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 1594a802631d..437fcd2f352f 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -38,7 +38,6 @@ struct ixp2000_flash_info { struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; struct resource *res; }; @@ -125,8 +124,6 @@ static int ixp2000_flash_remove(struct platform_device *dev) if (info->map.map_priv_1) iounmap((void *) info->map.map_priv_1); - kfree(info->partitions); - if (info->res) { release_resource(info->res); kfree(info->res); @@ -229,13 +226,7 @@ static int ixp2000_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); - if (err > 0) { - err = mtd_device_register(info->mtd, info->partitions, err); - if(err) - dev_err(&dev->dev, "Could not parse partitions\n"); - } - + err = mtd_device_parse_register(info->mtd, probes, 0, NULL, 0); if (err) goto Error; From bc413f11ddf2c692cc533f474d28a154abe4541f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:47 +0400 Subject: [PATCH 0223/1596] mtd: ixp4xx.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/ixp4xx.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 155b21942f47..30409015a3de 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -145,7 +145,6 @@ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) struct ixp4xx_flash_info { struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; struct resource *res; }; @@ -168,8 +167,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev) if (info->map.virt) iounmap(info->map.virt); - kfree(info->partitions); - if (info->res) { release_resource(info->res); kfree(info->res); @@ -185,8 +182,6 @@ static int ixp4xx_flash_probe(struct platform_device *dev) { struct flash_platform_data *plat = dev->dev.platform_data; struct ixp4xx_flash_info *info; - const char *part_type = NULL; - int nr_parts = 0; int err = -1; if (!plat) @@ -252,28 +247,12 @@ static int ixp4xx_flash_probe(struct platform_device *dev) /* Use the fast version */ info->map.write = ixp4xx_write16; - nr_parts = parse_mtd_partitions(info->mtd, probes, &info->partitions, - dev->resource->start); - if (nr_parts > 0) { - part_type = "dynamic"; - } else { - info->partitions = plat->parts; - nr_parts = plat->nr_parts; - part_type = "static"; - } - if (nr_parts == 0) - printk(KERN_NOTICE "IXP4xx flash: no partition info " - "available, registering whole flash\n"); - else - printk(KERN_NOTICE "IXP4xx flash: using %s partition " - "definition\n", part_type); - - err = mtd_device_register(info->mtd, info->partitions, nr_parts); - if (err) + err = mtd_device_parse_register(info->mtd, probes, dev->resource->start, + plat->parts, plat->nr_parts); + if (err) { printk(KERN_ERR "Could not parse partitions\n"); - - if (err) goto Error; + } return 0; From ca97dec2ab5c87e9fbdf7e882e1820004a3966fa Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:49 +0400 Subject: [PATCH 0224/1596] mtd: lantiq-flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/lantiq-flash.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 57ea3fe2296f..f7507844c556 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -112,9 +112,7 @@ ltq_mtd_probe(struct platform_device *pdev) { struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); struct ltq_mtd *ltq_mtd; - struct mtd_partition *parts; struct resource *res; - int nr_parts = 0; struct cfi_private *cfi; int err; @@ -170,16 +168,8 @@ ltq_mtd_probe(struct platform_device *pdev) cfi->addr_unlock1 ^= 1; cfi->addr_unlock2 ^= 1; - nr_parts = parse_mtd_partitions(ltq_mtd->mtd, NULL, &parts, 0); - if (nr_parts > 0) { - dev_info(&pdev->dev, - "using %d partitions from cmdline", nr_parts); - } else { - nr_parts = ltq_mtd_data->nr_parts; - parts = ltq_mtd_data->parts; - } - - err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts); + err = mtd_device_parse_register(ltq_mtd->mtd, NULL, 0, + ltq_mtd_data->parts, ltq_mtd_data->nr_parts); if (err) { dev_err(&pdev->dev, "failed to add partitions\n"); goto err_destroy; From 6e6e44c8bf73cdbd3600f18cb195fc965c0f1b45 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:50 +0400 Subject: [PATCH 0225/1596] mtd: latch-addr-flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/latch-addr-flash.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 09cf704ea02e..119baa7d7477 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -33,9 +33,6 @@ struct latch_addr_flash_info { /* cache; could be found out of res */ unsigned long win_mask; - int nr_parts; - struct mtd_partition *parts; - spinlock_t lock; }; @@ -110,8 +107,6 @@ static int latch_addr_flash_remove(struct platform_device *dev) latch_addr_data = dev->dev.platform_data; if (info->mtd != NULL) { - if (info->nr_parts) - kfree(info->parts); mtd_device_unregister(info->mtd); map_destroy(info->mtd); } @@ -204,20 +199,8 @@ static int __devinit latch_addr_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - err = parse_mtd_partitions(info->mtd, NULL, &info->parts, 0); - if (err > 0) { - mtd_device_register(info->mtd, info->parts, err); - return 0; - } - if (latch_addr_data->nr_parts) { - pr_notice("Using latch-addr-flash partition information\n"); - mtd_device_register(info->mtd, - latch_addr_data->parts, - latch_addr_data->nr_parts); - return 0; - } - - mtd_device_register(info->mtd, NULL, 0); + mtd_device_parse_register(info->mtd, NULL, 0, + latch_addr_data->parts, latch_addr_data->nr_parts); return 0; iounmap: From d45fd1218897b05dfa977a49f72e6f7bdc3e2471 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:58 +0400 Subject: [PATCH 0226/1596] mtd: physmap.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Artem: tweaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/physmap.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 2174d103297e..66e8200079c2 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -27,8 +27,6 @@ struct physmap_flash_info { struct mtd_info *mtd[MAX_RESOURCES]; struct mtd_info *cmtd; struct map_info map[MAX_RESOURCES]; - int nr_parts; - struct mtd_partition *parts; }; static int physmap_flash_remove(struct platform_device *dev) @@ -46,8 +44,6 @@ static int physmap_flash_remove(struct platform_device *dev) if (info->cmtd) { mtd_device_unregister(info->cmtd); - if (info->nr_parts) - kfree(info->parts); if (info->cmtd != info->mtd[0]) mtd_concat_destroy(info->cmtd); } @@ -175,23 +171,8 @@ static int physmap_flash_probe(struct platform_device *dev) if (err) goto err_out; - err = parse_mtd_partitions(info->cmtd, part_probe_types, - &info->parts, 0); - if (err > 0) { - mtd_device_register(info->cmtd, info->parts, err); - info->nr_parts = err; - return 0; - } - - if (physmap_data->nr_parts) { - printk(KERN_NOTICE "Using physmap partition information\n"); - mtd_device_register(info->cmtd, physmap_data->parts, - physmap_data->nr_parts); - return 0; - } - - mtd_device_register(info->cmtd, NULL, 0); - + mtd_device_parse_register(info->cmtd, part_probe_types, 0, + physmap_data->parts, physmap_data->nr_parts); return 0; err_out: From 74fb3ab9330ee4dd1a3ddf19cd0f3ef1202376d9 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:01 +0400 Subject: [PATCH 0227/1596] mtd: plat-ram.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/plat-ram.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 9ca1eccba4bc..94f553489725 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -44,8 +44,6 @@ struct platram_info { struct device *dev; struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; - bool free_partitions; struct resource *area; struct platdata_mtd_ram *pdata; }; @@ -95,10 +93,6 @@ static int platram_remove(struct platform_device *pdev) if (info->mtd) { mtd_device_unregister(info->mtd); - if (info->partitions) { - if (info->free_partitions) - kfree(info->partitions); - } map_destroy(info->mtd); } @@ -228,21 +222,8 @@ static int platram_probe(struct platform_device *pdev) /* check to see if there are any available partitions, or wether * to add this device whole */ - if (!pdata->nr_partitions) { - /* try to probe using the supplied probe type */ - if (pdata->probes) { - err = parse_mtd_partitions(info->mtd, pdata->probes, - &info->partitions, 0); - info->free_partitions = 1; - if (err > 0) - err = mtd_device_register(info->mtd, - info->partitions, err); - } - } - /* use the static mapping */ - else - err = mtd_device_register(info->mtd, pdata->partitions, - pdata->nr_partitions); + err = mtd_device_parse_register(info->mtd, pdata->probes, 0, + pdata->partitions, pdata->nr_partitions); if (!err) dev_info(&pdev->dev, "registered mtd device\n"); From 6fcdc92fce81eadcee262a7a66bf3207314fab87 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:03 +0400 Subject: [PATCH 0228/1596] mtd: pxa2xx-flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/pxa2xx-flash.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 7ae137d4b998..411a17df9fc1 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -41,8 +41,6 @@ static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from, } struct pxa2xx_flash_info { - struct mtd_partition *parts; - int nr_parts; struct mtd_info *mtd; struct map_info map; }; @@ -55,9 +53,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) { struct flash_platform_data *flash = pdev->dev.platform_data; struct pxa2xx_flash_info *info; - struct mtd_partition *parts; struct resource *res; - int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -71,8 +67,6 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) info->map.bankwidth = flash->width; info->map.phys = res->start; info->map.size = resource_size(res); - info->parts = flash->parts; - info->nr_parts = flash->nr_parts; info->map.virt = ioremap(info->map.phys, info->map.size); if (!info->map.virt) { @@ -104,18 +98,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) } info->mtd->owner = THIS_MODULE; - ret = parse_mtd_partitions(info->mtd, probes, &parts, 0); - - if (ret > 0) { - info->nr_parts = ret; - info->parts = parts; - } - - if (!info->nr_parts) - printk("Registering %s as whole device\n", - info->map.name); - - mtd_device_register(info->mtd, info->parts, info->nr_parts); + mtd_device_parse_register(info->mtd, probes, 0, NULL, 0); platform_set_drvdata(pdev, info); return 0; @@ -133,7 +116,6 @@ static int __devexit pxa2xx_flash_remove(struct platform_device *dev) iounmap(info->map.virt); if (info->map.cached) iounmap(info->map.cached); - kfree(info->parts); kfree(info); return 0; } From c77d8092c761bc0ee219fd869e6cde876e2b7aa4 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:04 +0400 Subject: [PATCH 0229/1596] mtd: rbtx4939-flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/rbtx4939-flash.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index 5d15b6b32265..0237f197fd12 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -25,8 +25,6 @@ struct rbtx4939_flash_info { struct mtd_info *mtd; struct map_info map; - int nr_parts; - struct mtd_partition *parts; }; static int rbtx4939_flash_remove(struct platform_device *dev) @@ -41,8 +39,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev) if (info->mtd) { struct rbtx4939_flash_data *pdata = dev->dev.platform_data; - if (info->nr_parts) - kfree(info->parts); mtd_device_unregister(info->mtd); map_destroy(info->mtd); } @@ -106,20 +102,11 @@ static int rbtx4939_flash_probe(struct platform_device *dev) info->mtd->owner = THIS_MODULE; if (err) goto err_out; - err = parse_mtd_partitions(info->mtd, NULL, &info->parts, 0); - if (err > 0) { - mtd_device_register(info->mtd, info->parts, err); - info->nr_parts = err; - return 0; - } + err = mtd_device_parse_register(info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); - if (pdata->nr_parts) { - pr_notice("Using rbtx4939 partition information\n"); - mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); - return 0; - } - - mtd_device_register(info->mtd, NULL, 0); + if (err) + goto err_out; return 0; err_out: From 769dc431869a021b85feca607c7800c59822de9c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:06 +0400 Subject: [PATCH 0230/1596] mtd: sa1100-flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/sa1100-flash.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index a9b5e0e5c4c5..fa9c0a9670cd 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -131,10 +131,8 @@ struct sa_subdev_info { }; struct sa_info { - struct mtd_partition *parts; struct mtd_info *mtd; int num_subdev; - unsigned int nr_parts; struct sa_subdev_info subdev[0]; }; @@ -231,8 +229,6 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla mtd_concat_destroy(info->mtd); } - kfree(info->parts); - for (i = info->num_subdev - 1; i >= 0; i--) sa1100_destroy_subdev(&info->subdev[i]); kfree(info); @@ -341,10 +337,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int __devinit sa1100_mtd_probe(struct platform_device *pdev) { struct flash_platform_data *plat = pdev->dev.platform_data; - struct mtd_partition *parts; - const char *part_type = NULL; struct sa_info *info; - int err, nr_parts = 0; + int err; if (!plat) return -ENODEV; @@ -358,26 +352,8 @@ static int __devinit sa1100_mtd_probe(struct platform_device *pdev) /* * Partition selection stuff. */ - nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0); - if (nr_parts > 0) { - info->parts = parts; - part_type = "dynamic"; - } else { - parts = plat->parts; - nr_parts = plat->nr_parts; - part_type = "static"; - } - - if (nr_parts == 0) - printk(KERN_NOTICE "SA1100 flash: no partition info " - "available, registering whole flash\n"); - else - printk(KERN_NOTICE "SA1100 flash: using %s partition " - "definition\n", part_type); - - mtd_device_register(info->mtd, parts, nr_parts); - - info->nr_parts = nr_parts; + mtd_device_parse_register(info->mtd, part_probes, 0, + plat->parts, plat->nr_parts); platform_set_drvdata(pdev, info); err = 0; From 7029eef8ba6ebf96c18c4b3138c35fcd1342a80a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:12 +0400 Subject: [PATCH 0231/1596] mtd: solutionengine.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/solutionengine.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index cbf6bade9354..496c40704aff 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -19,8 +19,6 @@ static struct mtd_info *flash_mtd; static struct mtd_info *eprom_mtd; -static struct mtd_partition *parsed_parts; - struct map_info soleng_eprom_map = { .name = "Solution Engine EPROM", .size = 0x400000, @@ -51,12 +49,14 @@ static struct mtd_partition superh_se_partitions[] = { .size = MTDPART_SIZ_FULL, } }; +#define NUM_PARTITIONS ARRAY_SIZE(superh_se_partitions) +#else +#define superh_se_partitions NULL +#define NUM_PARTITIONS 0 #endif /* CONFIG_MTD_SUPERH_RESERVE */ static int __init init_soleng_maps(void) { - int nr_parts = 0; - /* First probe at offset 0 */ soleng_flash_map.phys = 0; soleng_flash_map.virt = (void __iomem *)P2SEGADDR(0); @@ -92,21 +92,8 @@ static int __init init_soleng_maps(void) mtd_device_register(eprom_mtd, NULL, 0); } - nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - -#ifdef CONFIG_MTD_SUPERH_RESERVE - if (nr_parts <= 0) { - printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", - CONFIG_MTD_SUPERH_RESERVE); - parsed_parts = superh_se_partitions; - nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts); - } -#endif /* CONFIG_MTD_SUPERH_RESERVE */ - - if (nr_parts > 0) - mtd_device_register(flash_mtd, parsed_parts, nr_parts); - else - mtd_device_register(flash_mtd, NULL, 0); + mtd_device_parse_register(flash_mtd, probes, 0, + superh_se_partitions, NUM_PARTITIONS); return 0; } @@ -118,10 +105,7 @@ static void __exit cleanup_soleng_maps(void) map_destroy(eprom_mtd); } - if (parsed_parts) - mtd_device_unregister(flash_mtd); - else - mtd_device_unregister(flash_mtd); + mtd_device_unregister(flash_mtd); map_destroy(flash_mtd); } From e062e2f52fed5bcf65b3228e991771a4a6030d85 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:20 +0400 Subject: [PATCH 0232/1596] mtd: wr_sbc82xx_flash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Artem: some tweaks, split one very long line while on it. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/wr_sbc82xx_flash.c | 33 ++++++++++++----------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 901ce968efae..aa7e0cb2893c 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -20,7 +20,6 @@ #include static struct mtd_info *sbcmtd[3]; -static struct mtd_partition *sbcmtd_parts[3]; struct map_info sbc82xx_flash_map[3] = { {.name = "Boot flash"}, @@ -101,6 +100,7 @@ static int __init init_sbc82xx_flash(void) for (i=0; i<3; i++) { int8_t flashcs[3] = { 0, 6, 1 }; int nr_parts; + struct mtd_partition *defparts; printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d", sbc82xx_flash_map[i].name, @@ -113,7 +113,8 @@ static int __init init_sbc82xx_flash(void) } printk(" at %08lx)\n", sbc82xx_flash_map[i].phys); - sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size); + sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, + sbc82xx_flash_map[i].size); if (!sbc82xx_flash_map[i].virt) { printk("Failed to ioremap\n"); @@ -129,24 +130,20 @@ static int __init init_sbc82xx_flash(void) sbcmtd[i]->owner = THIS_MODULE; - nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes, - &sbcmtd_parts[i], 0); - if (nr_parts > 0) { - mtd_device_register(sbcmtd[i], sbcmtd_parts[i], - nr_parts); - continue; - } - /* No partitioning detected. Use default */ if (i == 2) { - mtd_device_register(sbcmtd[i], NULL, 0); + defparts = NULL; + nr_parts = 0; } else if (i == bigflash) { - mtd_device_register(sbcmtd[i], bigflash_parts, - ARRAY_SIZE(bigflash_parts)); + defparts = bigflash_parts; + nr_parts = ARRAY_SIZE(bigflash_parts); } else { - mtd_device_register(sbcmtd[i], smallflash_parts, - ARRAY_SIZE(smallflash_parts)); + defparts = smallflash_parts; + nr_parts = ARRAY_SIZE(smallflash_parts); } + + mtd_device_parse_register(sbcmtd[i], part_probes, 0, + defparts, nr_parts); } return 0; } @@ -159,12 +156,8 @@ static void __exit cleanup_sbc82xx_flash(void) if (!sbcmtd[i]) continue; - if (i<2 || sbcmtd_parts[i]) - mtd_device_unregister(sbcmtd[i]); - else - mtd_device_unregister(sbcmtd[i]); + mtd_device_unregister(sbcmtd[i]); - kfree(sbcmtd_parts[i]); map_destroy(sbcmtd[i]); iounmap((void *)sbc82xx_flash_map[i].virt); From ef5d79f1e15ded65af7a75fc464d5dd246a912c7 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:23 +0400 Subject: [PATCH 0233/1596] mtd: atmel_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/atmel_nand.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 47ece8e06e17..b1381437a957 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -492,8 +492,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) struct resource *regs; struct resource *mem; int res; - struct mtd_partition *partitions = NULL; - int num_partitions = 0; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { @@ -652,24 +650,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev) } mtd->name = "atmel_nand"; - num_partitions = parse_mtd_partitions(mtd, NULL, &partitions, 0); - if (num_partitions <= 0 && host->board->parts) { - partitions = host->board->parts; - num_partitions = host->board->num_parts; - } - - if ((!partitions) || (num_partitions == 0)) { - printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n"); - res = -ENXIO; - goto err_no_partitions; - } - - res = mtd_device_register(mtd, partitions, num_partitions); + res = mtd_device_parse_register(mtd, NULL, 0, + host->board->parts, host->board->num_parts); if (!res) return res; -err_no_partitions: - nand_release(mtd); err_scan_tail: err_scan_ident: err_no_card: From 58171cb1422ed72192cde5573f26e6bd3c5c98f0 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:27 +0400 Subject: [PATCH 0234/1596] mtd: bcm_umi_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/bcm_umi_nand.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index b1b7b16a843b..a8ae89865a86 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -489,23 +489,8 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) } /* Register the partitions */ - { - int nr_partitions; - struct mtd_partition *partition_info; - - board_mtd->name = "bcm_umi-nand"; - nr_partitions = parse_mtd_partitions(board_mtd, NULL, - &partition_info, 0); - - if (nr_partitions <= 0) { - printk(KERN_ERR "BCM UMI NAND: Too few partitions - %d\n", - nr_partitions); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return -EIO; - } - mtd_device_register(board_mtd, partition_info, nr_partitions); - } + board_mtd->name = "bcm_umi-nand"; + mtd_device_parse_register(board_mtd, NULL, 0, NULL, 0); /* Return happy */ return 0; From 4d32de81382c5a0ee74b5ca5996f27111960a48d Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:29 +0400 Subject: [PATCH 0235/1596] mtd: cafe_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Fixed by Brian Norris Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/cafe_nand.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 88ac4b598abc..f6eb66432c81 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -57,7 +57,6 @@ struct cafe_priv { struct nand_chip nand; - struct mtd_partition *parts; struct pci_dev *pdev; void __iomem *mmio; struct rs_control *rs; @@ -630,8 +629,6 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, struct cafe_priv *cafe; uint32_t ctrl; int err = 0; - struct mtd_partition *parts; - int nr_parts; /* Very old versions shared the same PCI ident for all three functions on the chip. Verify the class too... */ @@ -800,16 +797,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, mtd); - /* We register the whole device first, separate from the partitions */ - mtd_device_register(mtd, NULL, 0); - mtd->name = "cafe_nand"; - nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); - if (nr_parts > 0) { - cafe->parts = parts; - dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts); - mtd_device_register(mtd, parts, nr_parts); - } + mtd_device_parse_register(mtd, part_probes, 0, NULL, 0); + goto out; out_irq: From 0b118f06df94eb5a14a70c93e0fc739a67f66ae6 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:30 +0400 Subject: [PATCH 0236/1596] mtd: cmx270_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Artem: tweaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/cmx270_nand.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index f8f5b7c0daf5..31308e694bd3 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -149,9 +149,6 @@ static int cmx270_device_ready(struct mtd_info *mtd) static int __init cmx270_init(void) { struct nand_chip *this; - const char *part_type; - struct mtd_partition *mtd_parts; - int mtd_parts_nb = 0; int ret; if (!(machine_is_armcore() && cpu_is_pxa27x())) @@ -220,22 +217,9 @@ static int __init cmx270_init(void) goto err_scan; } - mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, NULL, - &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - - if (!mtd_parts_nb) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } - /* Register the partitions */ - pr_notice("Using %s partition definition\n", part_type); - ret = mtd_device_register(cmx270_nand_mtd, mtd_parts, mtd_parts_nb); + ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, 0, + partition_info, NUM_PARTITIONS); if (ret) goto err_scan; From bbd86c9c33c8d1549cbad5077c5dbaeec8a5cae8 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:31 +0400 Subject: [PATCH 0237/1596] mtd: cs553x_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Artem: tewaked the patch Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/cs553x_nand.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index b2bdf72a9f19..414afa793563 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -283,8 +283,6 @@ static int __init cs553x_init(void) int err = -ENXIO; int i; uint64_t val; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = NULL; /* If the CPU isn't a Geode GX or LX, abort */ if (!is_geode()) @@ -314,11 +312,9 @@ static int __init cs553x_init(void) do mtdconcat etc. if we want to. */ for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { if (cs553x_mtd[i]) { - /* If any devices registered, return success. Else the last error. */ - mtd_parts_nb = parse_mtd_partitions(cs553x_mtd[i], NULL, &mtd_parts, 0); - mtd_device_register(cs553x_mtd[i], mtd_parts, - mtd_parts_nb); + mtd_device_parse_register(cs553x_mtd[i], NULL, 0, + NULL, 0); err = 0; } } From 5b55b1eb21a5aba9c6cf4e0325ac9e4dffa89435 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:32 +0400 Subject: [PATCH 0238/1596] mtd: davinci_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/davinci_nand.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 70c92a527f6b..c153e1f77f90 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -57,7 +57,6 @@ struct davinci_nand_info { struct device *dev; struct clk *clk; - bool partitioned; bool is_readmode; @@ -530,8 +529,6 @@ static int __init nand_davinci_probe(struct platform_device *pdev) int ret; uint32_t val; nand_ecc_modes_t ecc_mode; - struct mtd_partition *mtd_parts = NULL; - int mtd_parts_nb = 0; /* insist on board-specific configuration */ if (!pdata) @@ -753,26 +750,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev) if (ret < 0) goto err_scan; - mtd_parts_nb = parse_mtd_partitions(&info->mtd, NULL, &mtd_parts, 0); - - if (mtd_parts_nb <= 0) { - mtd_parts = pdata->parts; - mtd_parts_nb = pdata->nr_parts; - } - - /* Register any partitions */ - if (mtd_parts_nb > 0) { - ret = mtd_device_register(&info->mtd, mtd_parts, - mtd_parts_nb); - if (ret == 0) - info->partitioned = true; - } - - /* If there's no partition info, just package the whole chip - * as a single MTD device. - */ - if (!info->partitioned) - ret = mtd_device_register(&info->mtd, NULL, 0) ? -ENODEV : 0; + ret = mtd_device_parse_register(&info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); if (ret < 0) goto err_scan; From 6cb03c9cb520186859a034e4e829fb591aea78b6 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:35 +0400 Subject: [PATCH 0239/1596] mtd: edb7312.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/edb7312.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 2f9374b38b90..0b1bb91d46a9 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -104,9 +104,6 @@ static int ep7312_device_ready(struct mtd_info *mtd) static int __init ep7312_init(void) { struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; void __iomem *ep7312_fio_base; /* Allocate memory for MTD device structure and private data */ @@ -156,20 +153,10 @@ static int __init ep7312_init(void) return -ENXIO; } ep7312_mtd->name = "edb7312-nand"; - mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, NULL, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - if (mtd_parts_nb == 0) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ep7312_mtd, mtd_parts, mtd_parts_nb); + mtd_device_register(ep7312_mtd, NULL, 0, + partition_info, NUM_PARTITIONS); /* Return happy */ return 0; From 0d04eda1430e9a796214bee644b7e05d99cfe613 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:38 +0400 Subject: [PATCH 0240/1596] mtd: fsmc_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Linus Walleij: fixed compilation breakage Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsmc_nand.c | 66 +++++------------------------------- 1 file changed, 9 insertions(+), 57 deletions(-) diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index a39c224eb12f..e53b76064133 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -146,7 +146,7 @@ static struct mtd_partition partition_info_16KB_blk[] = { { .name = "Root File System", .offset = 0x460000, - .size = 0, + .size = MTDPART_SIZ_FULL, }, }; @@ -173,7 +173,7 @@ static struct mtd_partition partition_info_128KB_blk[] = { { .name = "Root File System", .offset = 0x800000, - .size = 0, + .size = MTDPART_SIZ_FULL, }, }; @@ -184,8 +184,6 @@ static struct mtd_partition partition_info_128KB_blk[] = { * @pid: Part ID on the AMBA PrimeCell format * @mtd: MTD info for a NAND flash. * @nand: Chip related info for a NAND flash. - * @partitions: Partition info for a NAND Flash. - * @nr_partitions: Total number of partition of a NAND flash. * * @ecc_place: ECC placing locations in oobfree type format. * @bank: Bank number for probed device. @@ -200,8 +198,6 @@ struct fsmc_nand_data { u32 pid; struct mtd_info mtd; struct nand_chip nand; - struct mtd_partition *partitions; - unsigned int nr_partitions; struct fsmc_eccplace *ecc_place; unsigned int bank; @@ -717,57 +713,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * Check for partition info passed */ host->mtd.name = "nand"; - host->nr_partitions = parse_mtd_partitions(&host->mtd, NULL, - &host->partitions, 0); - if (host->nr_partitions <= 0) { - /* - * Check if partition info passed via command line - */ - if (pdata->partitions) { - host->partitions = pdata->partitions; - host->nr_partitions = pdata->nr_partitions; - } else { - struct mtd_partition *partition; - int i; - - /* Select the default partitions info */ - switch (host->mtd.size) { - case 0x01000000: - case 0x02000000: - case 0x04000000: - host->partitions = partition_info_16KB_blk; - host->nr_partitions = - sizeof(partition_info_16KB_blk) / - sizeof(struct mtd_partition); - break; - case 0x08000000: - case 0x10000000: - case 0x20000000: - case 0x40000000: - host->partitions = partition_info_128KB_blk; - host->nr_partitions = - sizeof(partition_info_128KB_blk) / - sizeof(struct mtd_partition); - break; - default: - ret = -ENXIO; - pr_err("Unsupported NAND size\n"); - goto err_probe; - } - - partition = host->partitions; - for (i = 0; i < host->nr_partitions; i++, partition++) { - if (partition->size == 0) { - partition->size = host->mtd.size - - partition->offset; - break; - } - } - } - } - - ret = mtd_device_register(&host->mtd, host->partitions, - host->nr_partitions); + ret = mtd_device_parse_register(&host->mtd, NULL, 0, + host->mtd.size <= 0x04000000 ? + partition_info_16KB_blk : + partition_info_128KB_blk, + host->mtd.size <= 0x04000000 ? + ARRAY_SIZE(partition_info_16KB_blk) : + ARRAY_SIZE(partition_info_128KB_blk)); if (ret) goto err_probe; From 4571c1396260d3f235d987f4acdadfba820f57bf Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:40 +0400 Subject: [PATCH 0241/1596] mtd: h1910.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/h1910.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 42f9177e36b1..5dc6f0d92f1a 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -81,9 +81,6 @@ static int h1910_device_ready(struct mtd_info *mtd) static int __init h1910_init(void) { struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; void __iomem *nandaddr; if (!machine_is_h1900()) @@ -136,18 +133,10 @@ static int __init h1910_init(void) iounmap((void *)nandaddr); return -ENXIO; } - mtd_parts_nb = parse_mtd_partitions(h1910_nand_mtd, NULL, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(h1910_nand_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(h1910_nand_mtd, NULL, 0, + partition_info, NUM_PARTITIONS); /* Return happy */ return 0; From 90ee1fb3ac918362402a06d0f71545111f374980 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:41 +0400 Subject: [PATCH 0242/1596] mtd: jz4740_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/jz4740_nand.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 920719cbdb55..e2664073a89b 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -295,8 +295,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) struct nand_chip *chip; struct mtd_info *mtd; struct jz_nand_platform_data *pdata = pdev->dev.platform_data; - struct mtd_partition *partition_info; - int num_partitions = 0; nand = kzalloc(sizeof(*nand), GFP_KERNEL); if (!nand) { @@ -369,12 +367,9 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) goto err_gpio_free; } - num_partitions = parse_mtd_partitions(mtd, NULL, &partition_info, 0); - if (num_partitions <= 0 && pdata) { - num_partitions = pdata->num_partitions; - partition_info = pdata->partitions; - } - ret = mtd_device_register(mtd, partition_info, num_partitions); + ret = mtd_device_parse_register(mtd, NULL, 0, + pdata ? pdata->partitions : NULL, + pdata ? pdata->num_partitions : 0); if (ret) { dev_err(&pdev->dev, "Failed to add mtd device\n"); From d4ed8f1222d5ada9da402cf312dc64e39c705da9 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:43 +0400 Subject: [PATCH 0243/1596] mtd: mxc_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/mxc_nand.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ca42c8f335b3..4c2bb4a4bf0b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -143,7 +143,6 @@ struct mxc_nand_host { struct mtd_info mtd; struct nand_chip nand; - struct mtd_partition *parts; struct device *dev; void *spare0; @@ -1044,7 +1043,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_host *host; struct resource *res; - int err = 0, __maybe_unused nr_parts = 0; + int err = 0; struct nand_ecclayout *oob_smallpage, *oob_largepage; /* Allocate memory for MTD device structure and private data */ @@ -1231,16 +1230,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) } /* Register the partitions */ - nr_parts = - parse_mtd_partitions(mtd, part_probes, &host->parts, 0); - if (nr_parts > 0) - mtd_device_register(mtd, host->parts, nr_parts); - else if (pdata->parts) - mtd_device_register(mtd, pdata->parts, pdata->nr_parts); - else { - pr_info("Registering %s as whole device\n", mtd->name); - mtd_device_register(mtd, NULL, 0); - } + mtd_device_parse_register(mtd, part_probes, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, host); From 69c85f1f66888e0ad532f8bb37db81ca1e7e56f0 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:55 +0400 Subject: [PATCH 0244/1596] mtd: omap2.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/omap2.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 8783c0800b5e..c5e33fdcbc86 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -112,7 +112,6 @@ struct omap_nand_info { struct nand_hw_control controller; struct omap_nand_platform_data *pdata; struct mtd_info mtd; - struct mtd_partition *parts; struct nand_chip nand; struct platform_device *pdev; @@ -1101,13 +1100,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) goto out_release_mem_region; } - err = parse_mtd_partitions(&info->mtd, NULL, &info->parts, 0); - if (err > 0) - mtd_device_register(&info->mtd, info->parts, err); - else if (pdata->parts) - mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); - else - mtd_device_register(&info->mtd, NULL, 0); + mtd_device_parse_register(&info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, &info->mtd); From c9dd375f553e6ff1862401decb1b585929285b56 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:55 +0400 Subject: [PATCH 0245/1596] mtd: orion_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/orion_nand.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 5c55981df3da..29f505adaf84 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -79,8 +79,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) struct resource *res; void __iomem *io_base; int ret = 0; - struct mtd_partition *partitions = NULL; - int num_part = 0; nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL); if (!nc) { @@ -131,14 +129,8 @@ static int __init orion_nand_probe(struct platform_device *pdev) } mtd->name = "orion_nand"; - num_part = parse_mtd_partitions(mtd, NULL, &partitions, 0); - /* If cmdline partitions have been passed, let them be used */ - if (num_part <= 0) { - num_part = board->nr_parts; - partitions = board->parts; - } - - ret = mtd_device_register(mtd, partitions, num_part); + ret = mtd_device_parse_register(mtd, NULL, 0, + board->parts, board->nr_parts); if (ret) { nand_release(mtd); goto no_dev; From 009c840770fda0165302e9853192a7f0677098b3 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:57 +0400 Subject: [PATCH 0246/1596] mtd: plat_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/plat_nand.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 746a723b4933..ea8e1234e0e2 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -21,8 +21,6 @@ struct plat_nand_data { struct nand_chip chip; struct mtd_info mtd; void __iomem *io_base; - int nr_parts; - struct mtd_partition *parts; }; /* @@ -100,21 +98,9 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) goto out; } - if (pdata->chip.part_probe_types) { - err = parse_mtd_partitions(&data->mtd, - pdata->chip.part_probe_types, - &data->parts, 0); - if (err > 0) { - mtd_device_register(&data->mtd, data->parts, err); - return 0; - } - } - if (pdata->chip.partitions) { - data->parts = pdata->chip.partitions; - err = mtd_device_register(&data->mtd, data->parts, - pdata->chip.nr_partitions); - } else - err = mtd_device_register(&data->mtd, NULL, 0); + err = mtd_device_parse_register(&data->mtd, + pdata->chip.part_probe_types, 0, + pdata->chip.partitions, pdata->chip.nr_partitions); if (!err) return err; @@ -144,8 +130,6 @@ static int __devexit plat_nand_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_release(&data->mtd); - if (data->parts && data->parts != pdata->chip.partitions) - kfree(data->parts); if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); iounmap(data->io_base); From 725b75a4acd34e39685483864e824b430e55e2ac Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:58 +0400 Subject: [PATCH 0247/1596] mtd: ppchameleonevb.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/ppchameleonevb.c | 42 ++++++++----------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 93766336ab79..7e52af51a198 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -191,9 +191,6 @@ static int ppchameleonevb_device_ready(struct mtd_info *minfo) static int __init ppchameleonevb_init(void) { struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; void __iomem *ppchameleon_fio_base; void __iomem *ppchameleonevb_fio_base; @@ -276,24 +273,13 @@ static int __init ppchameleonevb_init(void) #endif ppchameleon_mtd->name = "ppchameleon-nand"; - mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, NULL, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - - if (mtd_parts_nb == 0) { - if (ppchameleon_mtd->size == NAND_SMALL_SIZE) - mtd_parts = partition_info_me; - else - mtd_parts = partition_info_hi; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ppchameleon_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(ppchameleon_mtd, NULL, 0, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : + partition_info_hi, + NUM_PARTITIONS); nand_evb_init: /**************************** @@ -377,21 +363,13 @@ static int __init ppchameleonevb_init(void) } ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME; - mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, NULL, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - - if (mtd_parts_nb == 0) { - mtd_parts = partition_info_evb; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(ppchameleonevb_mtd, NULL, 0, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : + partition_info_hi, + NUM_PARTITIONS); /* Return happy */ return 0; From ee0f6a15b3f9246ae11e581cb9dae8fb2cc5da5c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:59 +0400 Subject: [PATCH 0248/1596] mtd: pxa3xx_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/pxa3xx_nand.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 5c3af2f72a62..b7db1b2021f2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1133,8 +1133,6 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; - struct mtd_partition *parts; - int nr_parts; pdata = pdev->dev.platform_data; if (!pdata) { @@ -1152,13 +1150,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) return -ENODEV; } - - nr_parts = parse_mtd_partitions(info->mtd, NULL, &parts, 0); - - if (nr_parts) - return mtd_device_register(info->mtd, parts, nr_parts); - - return mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); + return mtd_device_parse_register(info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); } #ifdef CONFIG_PM From 599501a749a1ca3baa94ac9714f06782f63439b0 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:01:02 +0400 Subject: [PATCH 0249/1596] mtd: s3c2410.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/s3c2410.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 17954baf12cd..b0f8e77834fe 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -748,21 +748,11 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *mtd, struct s3c2410_nand_set *set) { - struct mtd_partition *part_info; - int nr_part = 0; + if (set) + mtd->mtd.name = set->name; - if (set == NULL) - return mtd_device_register(&mtd->mtd, NULL, 0); - - mtd->mtd.name = set->name; - nr_part = parse_mtd_partitions(&mtd->mtd, NULL, &part_info, 0); - - if (nr_part <= 0 && set->nr_partitions > 0) { - nr_part = set->nr_partitions; - part_info = set->partitions; - } - - return mtd_device_register(&mtd->mtd, part_info, nr_part); + return mtd_device_parse_register(&mtd->mtd, NULL, 0, + set->partitions, set->nr_partitions); } /** From 3af55a89912e7e4b2a09d4c8c04fd884a6cf151f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:01:03 +0400 Subject: [PATCH 0250/1596] mtd: sharpsl.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/sharpsl.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index b3377f88326e..619d2a504788 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -109,8 +109,6 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, static int __devinit sharpsl_nand_probe(struct platform_device *pdev) { struct nand_chip *this; - struct mtd_partition *sharpsl_partition_info; - int nr_partitions; struct resource *r; int err = 0; struct sharpsl_nand *sharpsl; @@ -182,14 +180,9 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) /* Register the partitions */ sharpsl->mtd.name = "sharpsl-nand"; - nr_partitions = parse_mtd_partitions(&sharpsl->mtd, NULL, &sharpsl_partition_info, 0); - if (nr_partitions <= 0) { - nr_partitions = data->nr_partitions; - sharpsl_partition_info = data->partitions; - } - err = mtd_device_register(&sharpsl->mtd, sharpsl_partition_info, - nr_partitions); + err = mtd_device_parse_register(&sharpsl->mtd, NULL, 0, + data->partitions, data->nr_partitions); if (err) goto err_add; From 68adef5db85d147943ed97bbd148a712b2323ecc Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:01:09 +0400 Subject: [PATCH 0251/1596] mtd: tmio_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/tmio_nand.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index b6ffad64cda5..beebd95f7690 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -378,8 +378,6 @@ static int tmio_probe(struct platform_device *dev) struct tmio_nand *tmio; struct mtd_info *mtd; struct nand_chip *nand_chip; - struct mtd_partition *parts; - int nbparts = 0; int retval; if (data == NULL) @@ -458,13 +456,9 @@ static int tmio_probe(struct platform_device *dev) goto err_scan; } /* Register the partitions */ - nbparts = parse_mtd_partitions(mtd, NULL, &parts, 0); - if (nbparts <= 0 && data) { - parts = data->partition; - nbparts = data->num_partitions; - } - - retval = mtd_device_register(mtd, parts, nbparts); + retval = mtd_device_parse_register(mtd, NULL, 0, + data ? data->partition : NULL, + data ? data->num_partitions : 0); if (!retval) return retval; From 9e58c5d42ff69e7d99cc8e37082f58ba44e7fa7d Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:01:09 +0400 Subject: [PATCH 0252/1596] mtd: txx9ndfmc.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/txx9ndfmc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 91b05b9a9086..ace46fdaef58 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -74,7 +74,6 @@ struct txx9ndfmc_drvdata { unsigned char hold; /* in gbusclock */ unsigned char spw; /* in gbusclock */ struct nand_hw_control hw_control; - struct mtd_partition *parts[MAX_TXX9NDFMC_DEV]; }; static struct platform_device *mtd_to_platdev(struct mtd_info *mtd) @@ -332,7 +331,6 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) struct txx9ndfmc_priv *txx9_priv; struct nand_chip *chip; struct mtd_info *mtd; - int nr_parts; if (!(plat->ch_mask & (1 << i))) continue; @@ -392,9 +390,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) } mtd->name = txx9_priv->mtdname; - nr_parts = parse_mtd_partitions(mtd, NULL, - &drvdata->parts[i], 0); - mtd_device_register(mtd, drvdata->parts[i], nr_parts); + mtd_device_parse_register(mtd, NULL, 0, NULL, 0); drvdata->mtds[i] = mtd; } @@ -420,7 +416,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev) txx9_priv = chip->priv; nand_release(mtd); - kfree(drvdata->parts[i]); kfree(txx9_priv->mtdname); kfree(txx9_priv); } From 92ffb00d11b24e69cc87a0c0aa5de172d9de8e13 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:01:10 +0400 Subject: [PATCH 0253/1596] mtd: onenand/generic.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/generic.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index bca1c496135f..8152a3160b12 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -32,7 +32,6 @@ struct onenand_info { struct mtd_info mtd; - struct mtd_partition *parts; struct onenand_chip onenand; }; @@ -71,13 +70,9 @@ static int __devinit generic_onenand_probe(struct platform_device *pdev) goto out_iounmap; } - err = parse_mtd_partitions(&info->mtd, NULL, &info->parts, 0); - if (err > 0) - mtd_device_register(&info->mtd, info->parts, err); - else if (err <= 0 && pdata && pdata->parts) - mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); - else - err = mtd_device_register(&info->mtd, NULL, 0); + err = mtd_device_parse_register(&info->mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); platform_set_drvdata(pdev, info); From 7d010d2e772e16ef35a9bc6d706ec1e40eac9f46 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:01:11 +0400 Subject: [PATCH 0254/1596] mtd: onenand/omap2.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Axel Lin : fixed build breakage Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/omap2.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 5ca2053f6027..06efa14cfa34 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -57,7 +57,6 @@ struct omap2_onenand { unsigned long phys_base; int gpio_irq; struct mtd_info mtd; - struct mtd_partition *parts; struct onenand_chip onenand; struct completion irq_done; struct completion dma_done; @@ -752,13 +751,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) if ((r = onenand_scan(&c->mtd, 1)) < 0) goto err_release_regulator; - r = parse_mtd_partitions(&c->mtd, NULL, &c->parts, 0); - if (r > 0) - r = mtd_device_register(&c->mtd, c->parts, r); - else if (pdata->parts != NULL) - r = mtd_device_register(&c->mtd, pdata->parts, pdata->nr_parts); - else - r = mtd_device_register(&c->mtd, NULL, 0); + r = mtd_device_parse_register(&c->mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); if (r) goto err_release_onenand; @@ -785,7 +780,6 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) err_free_cs: gpmc_cs_free(c->gpmc_cs); err_kfree: - kfree(c->parts); kfree(c); return r; @@ -808,7 +802,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) iounmap(c->onenand.base); release_mem_region(c->phys_base, ONENAND_IO_SIZE); gpmc_cs_free(c->gpmc_cs); - kfree(c->parts); kfree(c); return 0; From f8214b80dacbb4d009b2c8968fe52aafb6ed55d4 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:01:16 +0400 Subject: [PATCH 0255/1596] mtd: onenand/samsung.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Axel Lin : fixed build error. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/samsung.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 78a08eae6adf..5474547eafc2 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -147,7 +147,6 @@ struct s3c_onenand { struct resource *dma_res; unsigned long phys_base; struct completion complete; - struct mtd_partition *parts; }; #define CMD_MAP_00(dev, addr) (dev->cmd_map(MAP_00, ((addr) << 1))) @@ -1015,13 +1014,9 @@ static int s3c_onenand_probe(struct platform_device *pdev) if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ) dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n"); - err = parse_mtd_partitions(mtd, NULL, &onenand->parts, 0); - if (err > 0) - mtd_device_register(mtd, onenand->parts, err); - else if (err <= 0 && pdata && pdata->parts) - mtd_device_register(mtd, pdata->parts, pdata->nr_parts); - else - err = mtd_device_register(mtd, NULL, 0); + err = mtd_device_parse_register(mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); platform_set_drvdata(pdev, mtd); From 3a8fb12ae9fdbb712f11f9c73e5d08dc34f82118 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:18 +0400 Subject: [PATCH 0256/1596] mtd: mtd_dataflash.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/mtd_dataflash.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 4d4a9cd10c33..8f6b02c43b43 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -637,8 +637,6 @@ add_dataflash_otp(struct spi_device *spi, char *name, struct flash_platform_data *pdata = spi->dev.platform_data; char *otp_tag = ""; int err = 0; - struct mtd_partition *parts; - int nr_parts = 0; priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) @@ -677,23 +675,10 @@ add_dataflash_otp(struct spi_device *spi, char *name, pagesize, otp_tag); dev_set_drvdata(&spi->dev, priv); - nr_parts = parse_mtd_partitions(device, NULL, &parts, 0); + err = mtd_device_parse_register(device, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); - if (nr_parts <= 0 && pdata && pdata->parts) { - parts = pdata->parts; - nr_parts = pdata->nr_parts; - } - - if (nr_parts > 0) { - priv->partitioned = 1; - err = mtd_device_register(device, parts, nr_parts); - goto out; - } - - if (mtd_device_register(device, NULL, 0) == 1) - err = -ENODEV; - -out: if (!err) return 0; From d117040be074fd1c019b751515f79efe99cd7d76 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 9 Jun 2011 14:54:41 +0400 Subject: [PATCH 0257/1596] mtd: edb7312: correctly pass MTD name to parsers cmdline partitions parser expects MTD name at mtd->name, instead of origin, while edb7312 passes MTDID as origin. Fix that. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/edb7312.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index fe42a212bb3e..b07acd69277a 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c @@ -88,8 +88,9 @@ static int __init init_edb7312nor(void) } if (mymtd) { mymtd->owner = THIS_MODULE; + mymtd->name = MTDID; - mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID); + mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); if (mtd_parts_nb > 0) part_type = "detected"; From e638275e18a929103bb087acb94d2b67eb0818e0 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 17 Jun 2011 19:06:33 +0800 Subject: [PATCH 0258/1596] mtd: onenand: remove redundant mtd_device_unregister before onenand_release onenand_release() will call mtd_device_unregister(), thus remove the redundant mtd_device_unregister() call before onenand_release(). Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/generic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 8152a3160b12..7813095264a5 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -97,7 +97,6 @@ static int __devexit generic_onenand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (info) { - mtd_device_unregister(&info->mtd); onenand_release(&info->mtd); release_mem_region(res->start, size); iounmap(info->onenand.base); From e8a0e41266e9c207ad8ac158cee9547ef1bc90ac Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 13 Jun 2011 22:16:44 +0200 Subject: [PATCH 0259/1596] jffs2: Avoid unneeded 'if' before kfree kfree() deals gracefully with NULL pointers, so it's pointless to test for one prior to calling it. This removes such a test from jffs2_scan_medium(). Signed-off-by: Jesper Juhl Signed-off-by: Artem Bityutskiy --- fs/jffs2/scan.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 8d8cd3419d02..28107ca136e4 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -275,9 +275,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) else c->mtd->unpoint(c->mtd, 0, c->mtd->size); #endif - if (s) - kfree(s); - + kfree(s); return ret; } From f722013ee9fd24623df31dec9a91a6d02c3e2f2f Mon Sep 17 00:00:00 2001 From: "THOMSON, Adam (Adam)" Date: Tue, 14 Jun 2011 16:52:38 +0200 Subject: [PATCH 0260/1596] mtd: nand_base: always initialise oob_poi before writing OOB data In nand_do_write_ops() code it is possible for a caller to provide ops.oobbuf populated and ops.mode == MTD_OOB_AUTO, which currently means that the chip->oob_poi buffer isn't initialised to all 0xFF. The nand_fill_oob() method then carries out the task of copying the provided OOB data to oob_poi, but with MTD_OOB_AUTO it skips areas marked as unavailable by the layout struct, including the bad block marker bytes. An example of this causing issues is when the last OOB data read was from the start of a bad block where the markers are not 0xFF, and the caller wishes to write new OOB data at the beginning of another block. In this scenario the caller would provide OOB data, but nand_fill_oob() would skip the bad block marker bytes in oob_poi before copying the OOB data provided by the caller. This means that when the OOB data is written back to NAND, the block is inadvertently marked as bad without the caller knowing. This has been witnessed when using YAFFS2 where tags are stored in the OOB. To avoid this oob_poi is always initialised to 0xFF to make sure no left over data is inadvertently written back to the OOB area. Credits to Brian Norris for fixing this patch. Signed-off-by: Adam Thomson Signed-off-by: Artem Bityutskiy Cc: stable@kernel.org [2.6.20+] --- drivers/mtd/nand/nand_base.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1525cd01dacd..408e1d0abfd1 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2088,14 +2088,22 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_fill_oob - [Internal] Transfer client buffer to oob - * @chip: nand chip structure + * @mtd: MTD device structure * @oob: oob data buffer * @len: oob data write length * @ops: oob ops structure */ -static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) +static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, + struct mtd_oob_ops *ops) { + struct nand_chip *chip = mtd->priv; + + /* + * Initialise to all 0xFF, to avoid the possibility of left over OOB + * data from a previous OOB read. + */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + switch (ops->mode) { case MTD_OOB_PLACE: @@ -2192,10 +2200,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; - /* If we're not given explicit OOB data, let it be 0xFF */ - if (likely(!oob)) - memset(chip->oob_poi, 0xff, mtd->oobsize); - /* Don't allow multipage oob writes with offset */ if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) return -EINVAL; @@ -2217,8 +2221,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) { size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(chip, oob, len, ops); + oob = nand_fill_oob(mtd, oob, len, ops); oobwritelen -= len; + } else { + /* We still need to erase leftover OOB data */ + memset(chip->oob_poi, 0xff, mtd->oobsize); } ret = chip->write_page(mtd, chip, wbuf, page, cached, @@ -2392,10 +2399,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (page == chip->pagebuf) chip->pagebuf = -1; - memset(chip->oob_poi, 0xff, mtd->oobsize); - nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); + nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); - memset(chip->oob_poi, 0xff, mtd->oobsize); if (status) return status; From c7975330154af17aecc167b33ca866b6b3d98918 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 10 Jun 2011 18:18:28 +0400 Subject: [PATCH 0261/1596] mtd: abstract last MTD partition parser argument Encapsulate last MTD partition parser argument into a separate structure. Currently it holds only 'origin' field for RedBoot parser, but will be extended in future to contain at least device_node for OF devices. Amended commentary to make kerneldoc happy Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/afs.c | 4 ++-- drivers/mtd/ar7part.c | 2 +- drivers/mtd/cmdlinepart.c | 4 ++-- drivers/mtd/mtdcore.c | 6 +++--- drivers/mtd/mtdpart.c | 7 ++++--- drivers/mtd/redboot.c | 13 ++++++------- include/linux/mtd/mtd.h | 3 ++- include/linux/mtd/partitions.h | 15 +++++++++++++-- 8 files changed, 33 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 302372c08b56..89a02f6f65dc 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -162,8 +162,8 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr) } static int parse_afs_partitions(struct mtd_info *mtd, - struct mtd_partition **pparts, - unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { struct mtd_partition *parts; u_int mask, off, idx, sz; diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index 6697a1ec72d0..71bfa2efb3ea 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -46,7 +46,7 @@ struct ar7_bin_rec { static int create_mtd_partitions(struct mtd_info *master, struct mtd_partition **pparts, - unsigned long origin) + struct mtd_part_parser_data *data) { struct ar7_bin_rec header; unsigned int offset; diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index be0c121f2f1b..1b11f94695e9 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -313,8 +313,8 @@ static int mtdpart_setup_real(char *s) * the first one in the chain if a NULL mtd_id is passed in. */ static int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { unsigned long offset; int i; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 13267477e4e9..e18639980f7a 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -457,7 +457,7 @@ EXPORT_SYMBOL_GPL(mtd_device_register); * @mtd: the MTD device to register * @types: the list of MTD partition probes to try, see * 'parse_mtd_partitions()' for more information - * @origin: start address of MTD device, %0 unless you are sure you need this. + * @parser_data: MTD partition parser-specific data * @parts: fallback partition information to register, if parsing fails; * only valid if %nr_parts > %0 * @nr_parts: the number of partitions in parts, if zero then the full @@ -480,14 +480,14 @@ EXPORT_SYMBOL_GPL(mtd_device_register); * Returns zero in case of success and a negative error code in case of failure. */ int mtd_device_parse_register(struct mtd_info *mtd, const char **types, - unsigned long origin, + struct mtd_part_parser_data *parser_data, const struct mtd_partition *parts, int nr_parts) { int err; struct mtd_partition *real_parts; - err = parse_mtd_partitions(mtd, types, &real_parts, origin); + err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); if (err <= 0 && nr_parts) { real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, GFP_KERNEL); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 2b71ccb00d39..34d582c2bdf3 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -736,7 +736,7 @@ static const char *default_mtd_part_types[] = {"cmdlinepart", NULL}; * @master: the master partition (describes whole MTD device) * @types: names of partition parsers to try or %NULL * @pparts: array of partitions found is returned here - * @origin: MTD device start address (use %0 if unsure) + * @data: MTD partition parser-specific data * * This function tries to find partition on MTD device @master. It uses MTD * partition parsers, specified in @types. However, if @types is %NULL, then @@ -750,7 +750,8 @@ static const char *default_mtd_part_types[] = {"cmdlinepart", NULL}; * point to an array containing this number of &struct mtd_info objects. */ int parse_mtd_partitions(struct mtd_info *master, const char **types, - struct mtd_partition **pparts, unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { struct mtd_part_parser *parser; int ret = 0; @@ -764,7 +765,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, parser = get_partition_parser(*types); if (!parser) continue; - ret = (*parser->parse_fn)(master, pparts, origin); + ret = (*parser->parse_fn)(master, pparts, data); if (ret > 0) { printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", ret, parser->name, master->name); diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 7a87d07cd79f..56e48ea7ff05 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -56,8 +56,8 @@ static inline int redboot_checksum(struct fis_image_desc *img) } static int parse_redboot_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - unsigned long fis_origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { int nrparts = 0; struct fis_image_desc *buf; @@ -197,11 +197,10 @@ static int parse_redboot_partitions(struct mtd_info *master, goto out; } new_fl->img = &buf[i]; - if (fis_origin) { - buf[i].flash_base -= fis_origin; - } else { - buf[i].flash_base &= master->size-1; - } + if (data && data->origin) + buf[i].flash_base -= data->origin; + else + buf[i].flash_base &= master->size-1; /* I'm sure the JFFS2 code has done me permanent damage. * I now think the following is _normal_ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index d28a241e7b55..b2b454b45cb5 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -323,13 +323,14 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd) /* Kernel-side ioctl definitions */ struct mtd_partition; +struct mtd_part_parser_data; extern int mtd_device_register(struct mtd_info *master, const struct mtd_partition *parts, int nr_parts); extern int mtd_device_parse_register(struct mtd_info *mtd, const char **part_probe_types, - unsigned long origin, + struct mtd_part_parser_data *parser_data, const struct mtd_partition *defparts, int defnr_parts); extern int mtd_device_unregister(struct mtd_info *master); diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 1431cf2609ed..5fdb963a5035 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -52,6 +52,15 @@ struct mtd_partition { struct mtd_info; +/** + * struct mtd_part_parser_data - used to pass data to MTD partition parsers. + * @origin: for RedBoot, start address of MTD device + */ +struct mtd_part_parser_data { + unsigned long origin; +}; + + /* * Functions dealing with the various ways of partitioning the space */ @@ -60,13 +69,15 @@ struct mtd_part_parser { struct list_head list; struct module *owner; const char *name; - int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long); + int (*parse_fn)(struct mtd_info *, struct mtd_partition **, + struct mtd_part_parser_data *); }; extern int register_mtd_parser(struct mtd_part_parser *parser); extern int deregister_mtd_parser(struct mtd_part_parser *parser); extern int parse_mtd_partitions(struct mtd_info *master, const char **types, - struct mtd_partition **pparts, unsigned long origin); + struct mtd_partition **pparts, + struct mtd_part_parser_data *data); #define put_partition_parser(p) do { module_put((p)->owner); } while(0) From d26c87d64eff271146b40b66c7de8cfeaf956707 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sun, 29 May 2011 21:32:33 +0400 Subject: [PATCH 0262/1596] mtd: prepare to convert of_mtd_parse_partitions to partition parser Prepare to convert of_mtd_parse_partitions() to usual partitions parser: 1) Register ofpart parser 2) Internally don't use passed device for error printing 3) Add device_node to mtd_part_parser_data struct 4) Move of_mtd_parse_partitions from __devinit to common text section 5) add ofpart to the default list of partition parsers Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdpart.c | 8 ++++++-- drivers/mtd/ofpart.c | 27 +++++++++++++++++++++++++-- include/linux/mtd/partitions.h | 5 ++++- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 34d582c2bdf3..9e8ee054135a 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -729,7 +729,11 @@ EXPORT_SYMBOL_GPL(deregister_mtd_parser); * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you * are changing this array! */ -static const char *default_mtd_part_types[] = {"cmdlinepart", NULL}; +static const char *default_mtd_part_types[] = { + "cmdlinepart", + "ofpart", + NULL +}; /** * parse_mtd_partitions - parse MTD partitions @@ -741,7 +745,7 @@ static const char *default_mtd_part_types[] = {"cmdlinepart", NULL}; * This function tries to find partition on MTD device @master. It uses MTD * partition parsers, specified in @types. However, if @types is %NULL, then * the default list of parsers is used. The default list contains only the - * "cmdlinepart" parser ATM. + * "cmdlinepart" and "ofpart" parsers ATM. * * This function may return: * o a negative error code in case of failure diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index a996718fa6b0..7c2c926e0bd7 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -20,7 +20,17 @@ #include #include -int __devinit of_mtd_parse_partitions(struct device *dev, +static int parse_ofpart_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + if (!data || !data->of_node) + return 0; + + return of_mtd_parse_partitions(NULL, data->of_node, pparts); +} + +int of_mtd_parse_partitions(struct device *dev, struct device_node *node, struct mtd_partition **pparts) { @@ -69,7 +79,7 @@ int __devinit of_mtd_parse_partitions(struct device *dev, if (!i) { of_node_put(pp); - dev_err(dev, "No valid partition found on %s\n", node->full_name); + pr_err("No valid partition found on %s\n", node->full_name); kfree(*pparts); *pparts = NULL; return -EINVAL; @@ -79,4 +89,17 @@ int __devinit of_mtd_parse_partitions(struct device *dev, } EXPORT_SYMBOL(of_mtd_parse_partitions); +static struct mtd_part_parser ofpart_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_ofpart_partitions, + .name = "ofpart", +}; + +static int __init ofpart_parser_init(void) +{ + return register_mtd_parser(&ofpart_parser); +} + +module_init(ofpart_parser_init); + MODULE_LICENSE("GPL"); diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 5fdb963a5035..ec60fd14670c 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -51,13 +51,16 @@ struct mtd_partition { struct mtd_info; +struct device_node; /** * struct mtd_part_parser_data - used to pass data to MTD partition parsers. * @origin: for RedBoot, start address of MTD device + * @of_node: for OF parsers, device node containing partitioning information */ struct mtd_part_parser_data { unsigned long origin; + struct device_node *of_node; }; @@ -85,7 +88,7 @@ struct device; struct device_node; #ifdef CONFIG_MTD_OF_PARTS -int __devinit of_mtd_parse_partitions(struct device *dev, +int of_mtd_parse_partitions(struct device *dev, struct device_node *node, struct mtd_partition **pparts); #else From 5f4ba9f9251a76753f50a4b9b8f49e6ec83d3d22 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:02:21 +0400 Subject: [PATCH 0263/1596] mtd: physmap_of: use ofpart through generic parsing Convert the driver to use ofpart partitions parsing through the generic parse_mtd_partitions(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/physmap_of.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index d251d1db129b..6a75743f8ea5 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -165,7 +165,8 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev, specifies the list of partition probers to use. If none is given then the default is use. These take precedence over other device tree information. */ -static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL }; +static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", + "ofpart", NULL }; static const char ** __devinit of_get_probes(struct device_node *dp) { const char *cp; @@ -218,6 +219,7 @@ static int __devinit of_flash_probe(struct platform_device *dev) int reg_tuple_size; struct mtd_info **mtd_list = NULL; resource_size_t res_size; + struct mtd_part_parser_data ppdata; match = of_match_device(of_flash_match, &dev->dev); if (!match) @@ -331,21 +333,16 @@ static int __devinit of_flash_probe(struct platform_device *dev) if (err) goto err_out; + ppdata.of_node = dp; part_probe_types = of_get_probes(dp); err = parse_mtd_partitions(info->cmtd, part_probe_types, - &info->parts, 0); + &info->parts, &ppdata); if (err < 0) { of_free_probes(part_probe_types); goto err_out; } of_free_probes(part_probe_types); - if (err == 0) { - err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts); - if (err < 0) - goto err_out; - } - if (err == 0) { err = parse_obsolete_partitions(dev, info, dp); if (err < 0) From ea6a4729869f899a904d862168bfc31e1451570e Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:02:20 +0400 Subject: [PATCH 0264/1596] mtd: m25p80: use ofpart through generic parsing Convert the driver to use ofpart partitions parsing through the generic parse_mtd_partitions(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/m25p80.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 70d5fcacc3fd..399c2349265f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -827,6 +827,7 @@ static int __devinit m25p_probe(struct spi_device *spi) unsigned i; struct mtd_partition *parts = NULL; int nr_parts = 0; + struct mtd_part_parser_data ppdata; /* Platform data helps sort out which chip type we have, as * well as how this board partitions it. If we don't have @@ -928,6 +929,7 @@ static int __devinit m25p_probe(struct spi_device *spi) if (info->flags & M25P_NO_ERASE) flash->mtd.flags |= MTD_NO_ERASE; + ppdata.of_node = spi->dev.of_node; flash->mtd.dev.parent = &spi->dev; flash->page_size = info->page_size; @@ -968,20 +970,13 @@ static int __devinit m25p_probe(struct spi_device *spi) /* partitions should match sector boundaries; and it may be good to * use readonly partitions for writeprotected sectors (BP2..BP0). */ - nr_parts = parse_mtd_partitions(&flash->mtd, NULL, &parts, 0); + nr_parts = parse_mtd_partitions(&flash->mtd, NULL, &parts, &ppdata); if (nr_parts <= 0 && data && data->parts) { parts = data->parts; nr_parts = data->nr_parts; } -#ifdef CONFIG_MTD_OF_PARTS - if (nr_parts <= 0 && spi->dev.of_node) { - nr_parts = of_mtd_parse_partitions(&spi->dev, - spi->dev.of_node, &parts); - } -#endif - if (nr_parts > 0) { for (i = 0; i < nr_parts; i++) { DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " From b6b0fae717bd01d6fcdcef70989c4bc9b77ac0c0 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:02:22 +0400 Subject: [PATCH 0265/1596] mtd: fsl_elbc_nand: use ofpart through generic parsing Convert the driver to use ofpart partitions parsing through the generic parse_mtd_partitions(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_elbc_nand.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index d4ea5fe013b7..4d225ba33a64 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -842,13 +842,15 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) struct resource res; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; static const char *part_probe_types[] - = { "cmdlinepart", "RedBoot", NULL }; + = { "cmdlinepart", "RedBoot", "ofpart", NULL }; struct mtd_partition *parts; int ret; int bank; struct device *dev; struct device_node *node = pdev->dev.of_node; + struct mtd_part_parser_data ppdata; + ppdata.of_node = pdev->dev.of_node; if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) return -ENODEV; lbc = fsl_lbc_ctrl_dev->regs; @@ -934,16 +936,10 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) /* First look for RedBoot table or partitions on the command * line, these take precedence over device tree information */ - ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, 0); + ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, &ppdata); if (ret < 0) goto err; - if (ret == 0) { - ret = of_mtd_parse_partitions(priv->dev, node, &parts); - if (ret < 0) - goto err; - } - mtd_device_register(&priv->mtd, parts, ret); printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n", From a454a296aa8e63f5e5c749343a99fd25c37a3c44 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:02:23 +0400 Subject: [PATCH 0266/1596] mtd: fsl_upm: use ofpart through generic parsing Convert the driver to use ofpart partitions parsing through the generic parse_mtd_partitions(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_upm.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 7c782ebd0f31..714d8318c6ad 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -158,6 +158,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, { int ret; struct device_node *flash_np; + struct mtd_part_parser_data ppdata; fun->chip.IO_ADDR_R = fun->io_base; fun->chip.IO_ADDR_W = fun->io_base; @@ -191,15 +192,9 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, if (ret) goto err; - ret = parse_mtd_partitions(&fun->mtd, NULL, &fun->parts, 0); + ppdata.of_node = flash_np; + ret = parse_mtd_partitions(&fun->mtd, NULL, &fun->parts, &ppdata); -#ifdef CONFIG_MTD_OF_PARTS - if (ret == 0) { - ret = of_mtd_parse_partitions(fun->dev, flash_np, &fun->parts); - if (ret < 0) - goto err; - } -#endif ret = mtd_device_register(&fun->mtd, fun->parts, ret); err: of_node_put(flash_np); From b3702ea4915363102870a6af60d06d655ca4a09d Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:02:24 +0400 Subject: [PATCH 0267/1596] mtd: mpc5121_nfc: use ofpart through generic parsing Convert the driver to use ofpart partitions parsing through the generic parse_mtd_partitions(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/mpc5121_nfc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 30f78ea8e993..9380f96716f4 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -661,6 +661,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) int resettime = 0; int retval = 0; int rev, len; + struct mtd_part_parser_data ppdata; /* * Check SoC revision. This driver supports only NFC @@ -725,6 +726,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) } mtd->name = "MPC5121 NAND"; + ppdata.of_node = dn; chip->dev_ready = mpc5121_nfc_dev_ready; chip->cmdfunc = mpc5121_nfc_command; chip->read_byte = mpc5121_nfc_read_byte; @@ -836,11 +838,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) dev_set_drvdata(dev, mtd); /* Register device in MTD */ - retval = parse_mtd_partitions(mtd, NULL, &parts, 0); -#ifdef CONFIG_MTD_OF_PARTS - if (retval == 0) - retval = of_mtd_parse_partitions(dev, dn, &parts); -#endif + retval = parse_mtd_partitions(mtd, NULL, &parts, &ppdata); if (retval < 0) { dev_err(dev, "Error parsing MTD partitions!\n"); devm_free_irq(dev, prv->irq, mtd); From 9d7948c50055e74b693ce9e99a709b2e5bbc1942 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:02:25 +0400 Subject: [PATCH 0268/1596] mtd: ndfc: use ofpart through generic parsing Convert the driver to use ofpart partitions parsing through the generic parse_mtd_partitions(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/ndfc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 70c04ffa573c..1528734b7616 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -161,6 +161,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, { struct device_node *flash_np; struct nand_chip *chip = &ndfc->chip; + struct mtd_part_parser_data ppdata; int ret; chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; @@ -188,6 +189,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (!flash_np) return -ENODEV; + ppdata->of_node = flash_np; ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev), flash_np->name); if (!ndfc->mtd.name) { @@ -199,17 +201,10 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (ret) goto err; - ret = parse_mtd_partitions(&ndfc->mtd, NULL, &ndfc->parts, 0); + ret = parse_mtd_partitions(&ndfc->mtd, NULL, &ndfc->parts, &ppdata); if (ret < 0) goto err; - if (ret == 0) { - ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np, - &ndfc->parts); - if (ret < 0) - goto err; - } - ret = mtd_device_register(&ndfc->mtd, ndfc->parts, ret); err: From 2cd9ea5256ecf2bc795d476598ac7f43f4b83a97 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:02:26 +0400 Subject: [PATCH 0269/1596] mtd: socrates_nand: use ofpart through generic parsing Convert the driver to use ofpart partitions parsing through the generic parse_mtd_partitions(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/socrates_nand.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 9023ac833fcf..f4f79ecb5ba3 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -166,6 +166,7 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) int res; struct mtd_partition *partitions = NULL; int num_partitions = 0; + struct mtd_part_parser_data ppdata; /* Allocate memory for the device structure (and zero it) */ host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL); @@ -191,6 +192,7 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) mtd->name = "socrates_nand"; mtd->owner = THIS_MODULE; mtd->dev.parent = &ofdev->dev; + ppdata.of_node = ofdev->dev.of_node; /*should never be accessed directly */ nand_chip->IO_ADDR_R = (void *)0xdeadbeef; @@ -223,22 +225,12 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) goto out; } - num_partitions = parse_mtd_partitions(mtd, NULL, &partitions, 0); + num_partitions = parse_mtd_partitions(mtd, NULL, &partitions, &ppdata); if (num_partitions < 0) { res = num_partitions; goto release; } - if (num_partitions == 0) { - num_partitions = of_mtd_parse_partitions(&ofdev->dev, - ofdev->dev.of_node, - &partitions); - if (num_partitions < 0) { - res = num_partitions; - goto release; - } - } - res = mtd_device_register(mtd, partitions, num_partitions); if (!res) return res; From 628376fb5369c353680f03f47705b1437ff8de80 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:05:33 +0400 Subject: [PATCH 0270/1596] mtd: drop of_mtd_parse_partitions() All users have been converted to call of_mtd_parse_partitions through parse_mtd_partitions() multiplexer. Drop obsolete API. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/ofpart.c | 20 +++++++++----------- include/linux/mtd/partitions.h | 16 ---------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 7c2c926e0bd7..24007f3c2c2f 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -24,20 +24,19 @@ static int parse_ofpart_partitions(struct mtd_info *master, struct mtd_partition **pparts, struct mtd_part_parser_data *data) { - if (!data || !data->of_node) - return 0; - - return of_mtd_parse_partitions(NULL, data->of_node, pparts); -} - -int of_mtd_parse_partitions(struct device *dev, - struct device_node *node, - struct mtd_partition **pparts) -{ + struct device_node *node; const char *partname; struct device_node *pp; int nr_parts, i; + + if (!data) + return 0; + + node = data->of_node; + if (!node) + return 0; + /* First count the subnodes */ pp = NULL; nr_parts = 0; @@ -87,7 +86,6 @@ int of_mtd_parse_partitions(struct device *dev, return nr_parts; } -EXPORT_SYMBOL(of_mtd_parse_partitions); static struct mtd_part_parser ofpart_parser = { .owner = THIS_MODULE, diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index ec60fd14670c..a8a961a8c8ff 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -84,22 +84,6 @@ extern int parse_mtd_partitions(struct mtd_info *master, const char **types, #define put_partition_parser(p) do { module_put((p)->owner); } while(0) -struct device; -struct device_node; - -#ifdef CONFIG_MTD_OF_PARTS -int of_mtd_parse_partitions(struct device *dev, - struct device_node *node, - struct mtd_partition **pparts); -#else -static inline int of_mtd_parse_partitions(struct device *dev, - struct device_node *node, - struct mtd_partition **pparts) -{ - return 0; -} -#endif - int mtd_is_partition(struct mtd_info *mtd); int mtd_add_partition(struct mtd_info *master, char *name, long long offset, long long length); From fbcf62a32be1e897a1d730af430758f881f8ef35 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 30 May 2011 01:26:17 +0400 Subject: [PATCH 0271/1596] mtd: physmap_of: move parse_obsolete_partitions to become separate parser Move parse_obsolete_partitions() to ofpart.c and register it as an ofoldpart partitions parser. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/physmap_of.c | 53 +------------------------ drivers/mtd/ofpart.c | 75 ++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 53 deletions(-) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 6a75743f8ea5..55c4e2eefdc6 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -40,51 +40,6 @@ struct of_flash { }; #define OF_FLASH_PARTS(info) ((info)->parts) -static int parse_obsolete_partitions(struct platform_device *dev, - struct of_flash *info, - struct device_node *dp) -{ - int i, plen, nr_parts; - const struct { - __be32 offset, len; - } *part; - const char *names; - - part = of_get_property(dp, "partitions", &plen); - if (!part) - return 0; /* No partitions found */ - - dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); - - nr_parts = plen / sizeof(part[0]); - - info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL); - if (!info->parts) - return -ENOMEM; - - names = of_get_property(dp, "partition-names", &plen); - - for (i = 0; i < nr_parts; i++) { - info->parts[i].offset = be32_to_cpu(part->offset); - info->parts[i].size = be32_to_cpu(part->len) & ~1; - if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */ - info->parts[i].mask_flags = MTD_WRITEABLE; - - if (names && (plen > 0)) { - int len = strlen(names) + 1; - - info->parts[i].name = (char *)names; - plen -= len; - names += len; - } else { - info->parts[i].name = "unnamed"; - } - - part++; - } - - return nr_parts; -} static int of_flash_remove(struct platform_device *dev) { @@ -166,7 +121,7 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev, default is use. These take precedence over other device tree information. */ static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", - "ofpart", NULL }; + "ofpart", "ofoldpart", NULL }; static const char ** __devinit of_get_probes(struct device_node *dp) { const char *cp; @@ -343,12 +298,6 @@ static int __devinit of_flash_probe(struct platform_device *dev) } of_free_probes(part_probe_types); - if (err == 0) { - err = parse_obsolete_partitions(dev, info, dp); - if (err < 0) - goto err_out; - } - mtd_device_register(info->cmtd, info->parts, err); kfree(mtd_list); diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 24007f3c2c2f..41c451842fd2 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -93,9 +93,82 @@ static struct mtd_part_parser ofpart_parser = { .name = "ofpart", }; +static int parse_ofoldpart_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *dp; + int i, plen, nr_parts; + const struct { + __be32 offset, len; + } *part; + const char *names; + + if (!data) + return 0; + + dp = data->of_node; + if (!dp) + return 0; + + part = of_get_property(dp, "partitions", &plen); + if (!part) + return 0; /* No partitions found */ + + pr_warning("Device tree uses obsolete partition map binding: %s\n", + dp->full_name); + + nr_parts = plen / sizeof(part[0]); + + *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); + if (!pparts) + return -ENOMEM; + + names = of_get_property(dp, "partition-names", &plen); + + for (i = 0; i < nr_parts; i++) { + (*pparts)[i].offset = be32_to_cpu(part->offset); + (*pparts)[i].size = be32_to_cpu(part->len) & ~1; + /* bit 0 set signifies read only partition */ + if (be32_to_cpu(part->len) & 1) + (*pparts)[i].mask_flags = MTD_WRITEABLE; + + if (names && (plen > 0)) { + int len = strlen(names) + 1; + + (*pparts)[i].name = (char *)names; + plen -= len; + names += len; + } else { + (*pparts)[i].name = "unnamed"; + } + + part++; + } + + return nr_parts; +} + +static struct mtd_part_parser ofoldpart_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_ofoldpart_partitions, + .name = "ofoldpart", +}; + static int __init ofpart_parser_init(void) { - return register_mtd_parser(&ofpart_parser); + int rc; + rc = register_mtd_parser(&ofpart_parser); + if (rc) + goto out; + + rc = register_mtd_parser(&ofoldpart_parser); + if (!rc) + return 0; + + deregister_mtd_parser(&ofoldpart_parser); +out: + return rc; } module_init(ofpart_parser_init); From f44dcbd06236ecc610bd03abeceac77a21cb019e Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:59 +0400 Subject: [PATCH 0272/1596] mtd: physmap_of.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/physmap_of.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 55c4e2eefdc6..7d65f9d3e690 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -34,13 +34,10 @@ struct of_flash_list { struct of_flash { struct mtd_info *cmtd; - struct mtd_partition *parts; int list_size; /* number of elements in of_flash_list */ struct of_flash_list list[0]; }; -#define OF_FLASH_PARTS(info) ((info)->parts) - static int of_flash_remove(struct platform_device *dev) { struct of_flash *info; @@ -56,11 +53,8 @@ static int of_flash_remove(struct platform_device *dev) mtd_concat_destroy(info->cmtd); } - if (info->cmtd) { - if (OF_FLASH_PARTS(info)) - kfree(OF_FLASH_PARTS(info)); + if (info->cmtd) mtd_device_unregister(info->cmtd); - } for (i = 0; i < info->list_size; i++) { if (info->list[i].mtd) @@ -290,16 +284,10 @@ static int __devinit of_flash_probe(struct platform_device *dev) ppdata.of_node = dp; part_probe_types = of_get_probes(dp); - err = parse_mtd_partitions(info->cmtd, part_probe_types, - &info->parts, &ppdata); - if (err < 0) { - of_free_probes(part_probe_types); - goto err_out; - } + mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, + NULL, 0); of_free_probes(part_probe_types); - mtd_device_register(info->cmtd, info->parts, err); - kfree(mtd_list); return 0; From 871770b5c857aa39e87785726ce3ec5a41cd387a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 17:59:16 +0400 Subject: [PATCH 0273/1596] mtd: m25p80.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/m25p80.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 399c2349265f..66a3555f07d9 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -88,7 +88,6 @@ struct m25p { struct spi_device *spi; struct mutex lock; struct mtd_info mtd; - unsigned partitioned:1; u16 page_size; u16 addr_width; u8 erase_opcode; @@ -825,8 +824,6 @@ static int __devinit m25p_probe(struct spi_device *spi) struct m25p *flash; struct flash_info *info; unsigned i; - struct mtd_partition *parts = NULL; - int nr_parts = 0; struct mtd_part_parser_data ppdata; /* Platform data helps sort out which chip type we have, as @@ -970,28 +967,9 @@ static int __devinit m25p_probe(struct spi_device *spi) /* partitions should match sector boundaries; and it may be good to * use readonly partitions for writeprotected sectors (BP2..BP0). */ - nr_parts = parse_mtd_partitions(&flash->mtd, NULL, &parts, &ppdata); - - if (nr_parts <= 0 && data && data->parts) { - parts = data->parts; - nr_parts = data->nr_parts; - } - - if (nr_parts > 0) { - for (i = 0; i < nr_parts; i++) { - DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " - "{.name = %s, .offset = 0x%llx, " - ".size = 0x%llx (%lldKiB) }\n", - i, parts[i].name, - (long long)parts[i].offset, - (long long)parts[i].size, - (long long)(parts[i].size >> 10)); - } - flash->partitioned = 1; - } - - return mtd_device_register(&flash->mtd, parts, nr_parts) == 1 ? - -ENODEV : 0; + return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, + data ? data->parts : NULL, + data ? data->nr_parts : 0); } From 99add4228fce515fe113282147a0aab74afa29ae Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:36 +0400 Subject: [PATCH 0274/1596] mtd: fsl_elbc_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_elbc_nand.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4d225ba33a64..915b4a4c06c2 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -843,7 +843,6 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "ofpart", NULL }; - struct mtd_partition *parts; int ret; int bank; struct device *dev; @@ -936,11 +935,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) /* First look for RedBoot table or partitions on the command * line, these take precedence over device tree information */ - ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, &ppdata); - if (ret < 0) - goto err; - - mtd_device_register(&priv->mtd, parts, ret); + mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata, + NULL, 0); printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n", (unsigned long long)res.start, priv->bank); From 73f36b3e251888ef224a3c90d3c408e02a1eb957 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:37 +0400 Subject: [PATCH 0275/1596] mtd: fsl_upm.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_upm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 714d8318c6ad..da92fed9f27b 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -193,9 +193,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, goto err; ppdata.of_node = flash_np; - ret = parse_mtd_partitions(&fun->mtd, NULL, &fun->parts, &ppdata); - - ret = mtd_device_register(&fun->mtd, fun->parts, ret); + ret = mtd_device_parse_register(&fun->mtd, NULL, &ppdata, NULL, 0); err: of_node_put(flash_np); return ret; From a9093f064eb053c1b9fca8b8026577c0b3b9aa8a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:42 +0400 Subject: [PATCH 0276/1596] mtd: mpc5121_nfc.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/mpc5121_nfc.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 9380f96716f4..5ede64706346 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -654,7 +654,6 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) struct mpc5121_nfc_prv *prv; struct resource res; struct mtd_info *mtd; - struct mtd_partition *parts; struct nand_chip *chip; unsigned long regs_paddr, regs_size; const __be32 *chips_no; @@ -838,15 +837,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) dev_set_drvdata(dev, mtd); /* Register device in MTD */ - retval = parse_mtd_partitions(mtd, NULL, &parts, &ppdata); - if (retval < 0) { - dev_err(dev, "Error parsing MTD partitions!\n"); - devm_free_irq(dev, prv->irq, mtd); - retval = -EINVAL; - goto error; - } - - retval = mtd_device_register(mtd, parts, retval); + retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (retval) { dev_err(dev, "Error adding MTD device!\n"); devm_free_irq(dev, prv->irq, mtd); From a9106497082c5b9d2b367159573127c2c9ced4b6 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:00:51 +0400 Subject: [PATCH 0277/1596] mtd: ndfc.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/ndfc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 1528734b7616..ee1713907b92 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -42,7 +42,6 @@ struct ndfc_controller { struct nand_chip chip; int chip_select; struct nand_hw_control ndfc_control; - struct mtd_partition *parts; }; static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS]; @@ -201,11 +200,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (ret) goto err; - ret = parse_mtd_partitions(&ndfc->mtd, NULL, &ndfc->parts, &ppdata); - if (ret < 0) - goto err; - - ret = mtd_device_register(&ndfc->mtd, ndfc->parts, ret); + ret = mtd_device_parse_register(&ndfc->mtd, NULL, &ppdata, NULL, 0); err: of_node_put(flash_np); From b2a5a4878e97119e3b64d4646fd138820d513c28 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 2 Jun 2011 18:01:07 +0400 Subject: [PATCH 0278/1596] mtd: socrates_nand.c: use mtd_device_parse_register Replace custom invocations of parse_mtd_partitions and mtd_device_register with common mtd_device_parse_register call. This would bring: standard handling of all errors, fallback to default partitions, etc. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/socrates_nand.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index f4f79ecb5ba3..0fb24f9c2327 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -164,8 +164,6 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) struct mtd_info *mtd; struct nand_chip *nand_chip; int res; - struct mtd_partition *partitions = NULL; - int num_partitions = 0; struct mtd_part_parser_data ppdata; /* Allocate memory for the device structure (and zero it) */ @@ -225,17 +223,10 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) goto out; } - num_partitions = parse_mtd_partitions(mtd, NULL, &partitions, &ppdata); - if (num_partitions < 0) { - res = num_partitions; - goto release; - } - - res = mtd_device_register(mtd, partitions, num_partitions); + res = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (!res) return res; -release: nand_release(mtd); out: From e1c10243df92822954b9b5e04d12dd2f23a39652 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Wed, 22 Jun 2011 14:16:49 +0900 Subject: [PATCH 0279/1596] mtd: OneNAND: Detect the correct NOP when 4KiB pagesize There are two different 4KiB pagesize chips KFM4G16Q4M series have NOP 4 with version ID 0x0131 But KFM4G16Q5M has NOP 1 with versoin ID 0x013e Note that Q5M means that it has NOP 1. Signed-off-by: Kyungmin Park Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/onenand_base.c | 15 +++++++++++++++ include/linux/mtd/onenand.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index ac9e959802a7..51800a7ef7f8 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -3429,6 +3429,19 @@ static void onenand_check_features(struct mtd_info *mtd) else if (numbufs == 1) { this->options |= ONENAND_HAS_4KB_PAGE; this->options |= ONENAND_HAS_CACHE_PROGRAM; + /* + * There are two different 4KiB pagesize chips + * and no way to detect it by H/W config values. + * + * To detect the correct NOP for each chips, + * It should check the version ID as workaround. + * + * Now it has as following + * KFM4G16Q4M has NOP 4 with version ID 0x0131 + * KFM4G16Q5M has NOP 1 with versoin ID 0x013e + */ + if ((this->version_id & 0xf) == 0xe) + this->options |= ONENAND_HAS_NOP_1; } case ONENAND_DEVICE_DENSITY_2Gb: @@ -4054,6 +4067,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->ecclayout = &onenand_oob_128; mtd->subpage_sft = 2; } + if (ONENAND_IS_NOP_1(this)) + mtd->subpage_sft = 0; break; case 64: this->ecclayout = &onenand_oob_64; diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 52b6f187bf49..4596503c9da9 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -184,6 +184,9 @@ struct onenand_chip { #define ONENAND_IS_CACHE_PROGRAM(this) \ (this->options & ONENAND_HAS_CACHE_PROGRAM) +#define ONENAND_IS_NOP_1(this) \ + (this->options & ONENAND_HAS_NOP_1) + /* Check byte access in OneNAND */ #define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1) @@ -195,6 +198,7 @@ struct onenand_chip { #define ONENAND_HAS_2PLANE (0x0004) #define ONENAND_HAS_4KB_PAGE (0x0008) #define ONENAND_HAS_CACHE_PROGRAM (0x0010) +#define ONENAND_HAS_NOP_1 (0x0020) #define ONENAND_SKIP_UNLOCK_CHECK (0x0100) #define ONENAND_PAGEBUF_ALLOC (0x1000) #define ONENAND_OOBBUF_ALLOC (0x2000) From ed764db2887aa90efb8c5a5d79775d5d18c26b27 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 23 Jun 2011 12:33:52 +0400 Subject: [PATCH 0280/1596] mtd: maps: drop edb7312 support EDB7312 isn't supported by mainline kernel, this driver wasn't working before recent fixes, the same functionality can be achieved via physmap, so drop it now. If the board support will ever be submitted to mainline, one either can revert this commit, or use physmap mtd map driver. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/Kconfig | 7 -- drivers/mtd/maps/Makefile | 1 - drivers/mtd/maps/edb7312.c | 135 ------------------------------------- 3 files changed, 143 deletions(-) delete mode 100644 drivers/mtd/maps/edb7312.c diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 46eca3b3bcb0..891a9e644542 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -392,13 +392,6 @@ config MTD_AUTCPU12 This enables access to the NV-RAM on autronix autcpu12 board. If you have such a board, say 'Y'. -config MTD_EDB7312 - tristate "CFI Flash device mapped on EDB7312" - depends on ARCH_EDB7312 && MTD_CFI - help - This enables access to the CFI Flash on the Cogent EDB7312 board. - If you have such a board, say 'Y' here. - config MTD_IMPA7 tristate "JEDEC Flash device mapped on impA7" depends on ARM && MTD_JEDECPROBE diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index d6379fea42b8..45dcb8b14f22 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -39,7 +39,6 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o -obj-$(CONFIG_MTD_EDB7312) += edb7312.o obj-$(CONFIG_MTD_IMPA7) += impa7.o obj-$(CONFIG_MTD_FORTUNET) += fortunet.o obj-$(CONFIG_MTD_UCLINUX) += uclinux.o diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c deleted file mode 100644 index b07acd69277a..000000000000 --- a/drivers/mtd/maps/edb7312.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Handle mapping of the NOR flash on Cogent EDB7312 boards - * - * Copyright 2002 SYSGO Real-Time Solutions GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define WINDOW_ADDR 0x00000000 /* physical properties of flash */ -#define WINDOW_SIZE 0x01000000 -#define BUSWIDTH 2 -#define FLASH_BLOCKSIZE_MAIN 0x20000 -#define FLASH_NUMBLOCKS_MAIN 128 -/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */ -#define PROBETYPES { "cfi_probe", NULL } - -#define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */ -#define MTDID "edb7312-nor" /* for mtdparts= partitioning */ - -static struct mtd_info *mymtd; - -struct map_info edb7312nor_map = { - .name = "NOR flash on EDB7312", - .size = WINDOW_SIZE, - .bankwidth = BUSWIDTH, - .phys = WINDOW_ADDR, -}; - -/* - * MTD partitioning stuff - */ -static struct mtd_partition static_partitions[3] = -{ - { - .name = "ARMboot", - .size = 0x40000, - .offset = 0 - }, - { - .name = "Kernel", - .size = 0x200000, - .offset = 0x40000 - }, - { - .name = "RootFS", - .size = 0xDC0000, - .offset = 0x240000 - }, -}; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static int mtd_parts_nb = 0; -static struct mtd_partition *mtd_parts = 0; - -static int __init init_edb7312nor(void) -{ - static const char *rom_probe_types[] = PROBETYPES; - const char **type; - const char *part_type = 0; - - printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", - WINDOW_SIZE, WINDOW_ADDR); - edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); - - if (!edb7312nor_map.virt) { - printk(MSG_PREFIX "failed to ioremap\n"); - return -EIO; - } - - simple_map_init(&edb7312nor_map); - - mymtd = 0; - type = rom_probe_types; - for(; !mymtd && *type; type++) { - mymtd = do_map_probe(*type, &edb7312nor_map); - } - if (mymtd) { - mymtd->owner = THIS_MODULE; - mymtd->name = MTDID; - - mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "detected"; - - if (mtd_parts_nb == 0) { - mtd_parts = static_partitions; - mtd_parts_nb = ARRAY_SIZE(static_partitions); - part_type = "static"; - } - - if (mtd_parts_nb == 0) - printk(KERN_NOTICE MSG_PREFIX "no partition info available\n"); - else - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", part_type); - /* Register the whole device first. */ - mtd_device_register(mymtd, NULL, 0); - mtd_device_register(mymtd, mtd_parts, mtd_parts_nb); - return 0; - } - - iounmap((void *)edb7312nor_map.virt); - return -ENXIO; -} - -static void __exit cleanup_edb7312nor(void) -{ - if (mymtd) { - mtd_device_unregister(mymtd); - map_destroy(mymtd); - } - if (edb7312nor_map.virt) { - iounmap((void *)edb7312nor_map.virt); - edb7312nor_map.virt = 0; - } -} - -module_init(init_edb7312nor); -module_exit(cleanup_edb7312nor); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger "); -MODULE_DESCRIPTION("Generic configurable MTD map driver"); From 050f01258319f2d2e66a131b7ddb6b5df5aa3af7 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 23 Jun 2011 12:33:52 +0400 Subject: [PATCH 0281/1596] mtd: nand: drop edb7312 support EDB7312 isn't supported by mainline kernel, so drop it now. If the board support will ever be submitted to mainline, one can revert this commit. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/Kconfig | 7 -- drivers/mtd/nand/Makefile | 1 - drivers/mtd/nand/edb7312.c | 188 ------------------------------------- 3 files changed, 196 deletions(-) delete mode 100644 drivers/mtd/nand/edb7312.c diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 4c3425235adc..17235d097774 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -83,13 +83,6 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR scratch register here to enable this feature. On Intel Moorestown boards, the scratch register is at 0xFF108018. -config MTD_NAND_EDB7312 - tristate "Support for Cirrus Logic EBD7312 evaluation board" - depends on ARCH_EDB7312 - help - This enables the driver for the Cirrus Logic EBD7312 evaluation - board to access the onboard NAND Flash. - config MTD_NAND_H1900 tristate "iPAQ H1900 flash" depends on ARCH_PXA diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 5745d831168e..c9334e9af912 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_DENALI) += denali.o -obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c deleted file mode 100644 index 0b1bb91d46a9..000000000000 --- a/drivers/mtd/nand/edb7312.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * drivers/mtd/nand/edb7312.c - * - * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) - * - * Derived from drivers/mtd/nand/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Overview: - * This is a device driver for the NAND flash device found on the - * CLEP7312 board which utilizes the Toshiba TC58V64AFT part. This is - * a 64Mibit (8MiB x 8 bits) NAND flash device. - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* for CLPS7111_VIRT_BASE */ -#include -#include - -/* - * MTD structure for EDB7312 board - */ -static struct mtd_info *ep7312_mtd = NULL; - -/* - * Values specific to the EDB7312 board (used with EP7312 processor) - */ -#define EP7312_FIO_PBASE 0x10000000 /* Phys address of flash */ -#define EP7312_PXDR 0x0001 /* - * IO offset to Port B data register - * where the CLE, ALE and NCE pins - * are wired to. - */ -#define EP7312_PXDDR 0x0041 /* - * IO offset to Port B data direction - * register so we can control the IO - * lines. - */ - -/* - * Module stuff - */ - -static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE; -static void __iomem *ep7312_pxdr = (void __iomem *)EP7312_PXDR; -static void __iomem *ep7312_pxddr = (void __iomem *)EP7312_PXDDR; - -/* - * Define static partitions for flash device - */ -static struct mtd_partition partition_info[] = { - {.name = "EP7312 Nand Flash", - .offset = 0, - .size = 8 * 1024 * 1024} -}; - -#define NUM_PARTITIONS 1 - -/* - * hardware specific access to control-lines - * - * NAND_NCE: bit 0 -> bit 6 (bit 7 = 1) - * NAND_CLE: bit 1 -> bit 4 - * NAND_ALE: bit 2 -> bit 5 - */ -static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *chip = mtd->priv; - - if (ctrl & NAND_CTRL_CHANGE) { - unsigned char bits = 0x80; - - bits |= (ctrl & (NAND_CLE | NAND_ALE)) << 3; - bits |= (ctrl & NAND_NCE) ? 0x00 : 0x40; - - clps_writeb((clps_readb(ep7312_pxdr) & 0xF0) | bits, - ep7312_pxdr); - } - if (cmd != NAND_CMD_NONE) - writeb(cmd, chip->IO_ADDR_W); -} - -/* - * read device ready pin - */ -static int ep7312_device_ready(struct mtd_info *mtd) -{ - return 1; -} - -/* - * Main initialization routine - */ -static int __init ep7312_init(void) -{ - struct nand_chip *this; - void __iomem *ep7312_fio_base; - - /* Allocate memory for MTD device structure and private data */ - ep7312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); - if (!ep7312_mtd) { - printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); - return -ENOMEM; - } - - /* map physical address */ - ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); - if (!ep7312_fio_base) { - printk("ioremap EDB7312 NAND flash failed\n"); - kfree(ep7312_mtd); - return -EIO; - } - - /* Get pointer to private data */ - this = (struct nand_chip *)(&ep7312_mtd[1]); - - /* Initialize structures */ - memset(ep7312_mtd, 0, sizeof(struct mtd_info)); - memset(this, 0, sizeof(struct nand_chip)); - - /* Link the private data with the MTD structure */ - ep7312_mtd->priv = this; - ep7312_mtd->owner = THIS_MODULE; - - /* - * Set GPIO Port B control register so that the pins are configured - * to be outputs for controlling the NAND flash. - */ - clps_writeb(0xf0, ep7312_pxddr); - - /* insert callbacks */ - this->IO_ADDR_R = ep7312_fio_base; - this->IO_ADDR_W = ep7312_fio_base; - this->cmd_ctrl = ep7312_hwcontrol; - this->dev_ready = ep7312_device_ready; - /* 15 us command delay time */ - this->chip_delay = 15; - - /* Scan to find existence of the device */ - if (nand_scan(ep7312_mtd, 1)) { - iounmap((void *)ep7312_fio_base); - kfree(ep7312_mtd); - return -ENXIO; - } - ep7312_mtd->name = "edb7312-nand"; - - /* Register the partitions */ - mtd_device_register(ep7312_mtd, NULL, 0, - partition_info, NUM_PARTITIONS); - - /* Return happy */ - return 0; -} - -module_init(ep7312_init); - -/* - * Clean up routine - */ -static void __exit ep7312_cleanup(void) -{ - struct nand_chip *this = (struct nand_chip *)&ep7312_mtd[1]; - - /* Release resources, unregister device */ - nand_release(ap7312_mtd); - - /* Release io resource */ - iounmap(this->IO_ADDR_R); - - /* Free the MTD device structure */ - kfree(ep7312_mtd); -} - -module_exit(ep7312_cleanup); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger "); -MODULE_DESCRIPTION("MTD map driver for Cogent EDB7312 board"); From 3165f44bcd4b987cbcc694af739ab955b561e05b Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 23 Jun 2011 15:23:08 +0400 Subject: [PATCH 0282/1596] mtd: hide parse_mtd_partitions There is no need to export parse_mtd_partitions() now , as it's fully handled by registration functions. So move the definition to private header and remove respective EXPORT_SYMBOL_GPL. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdcore.h | 3 +++ drivers/mtd/mtdpart.c | 1 - include/linux/mtd/partitions.h | 3 --- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index 0ed6126b4c1f..961a38408542 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -15,6 +15,9 @@ extern int del_mtd_device(struct mtd_info *mtd); extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); extern int del_mtd_partitions(struct mtd_info *); +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data); #define mtd_for_each_device(mtd) \ for ((mtd) = __mtd_next_device(0); \ diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 9e8ee054135a..6997c6cdc471 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -778,7 +778,6 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, } return ret; } -EXPORT_SYMBOL_GPL(parse_mtd_partitions); int mtd_is_partition(struct mtd_info *mtd) { diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index a8a961a8c8ff..c98d6b858c2c 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -78,9 +78,6 @@ struct mtd_part_parser { extern int register_mtd_parser(struct mtd_part_parser *parser); extern int deregister_mtd_parser(struct mtd_part_parser *parser); -extern int parse_mtd_partitions(struct mtd_info *master, const char **types, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data); #define put_partition_parser(p) do { module_put((p)->owner); } while(0) From 953b3bd1911260b8acd8f35fa26440c1a943e59a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 23 Jun 2011 15:26:14 +0400 Subject: [PATCH 0283/1596] mtd: remove put_partition_parser() from public header There is no need to pollute public header with a definition private to mtdpart.c. Move it from mtd/partitions.h to mtdpart.c Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdpart.c | 2 ++ include/linux/mtd/partitions.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 6997c6cdc471..c90b7ba362d7 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -706,6 +706,8 @@ static struct mtd_part_parser *get_partition_parser(const char *name) return ret; } +#define put_partition_parser(p) do { module_put((p)->owner); } while (0) + int register_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index c98d6b858c2c..2475228c1158 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -79,8 +79,6 @@ struct mtd_part_parser { extern int register_mtd_parser(struct mtd_part_parser *parser); extern int deregister_mtd_parser(struct mtd_part_parser *parser); -#define put_partition_parser(p) do { module_put((p)->owner); } while(0) - int mtd_is_partition(struct mtd_info *mtd); int mtd_add_partition(struct mtd_info *master, char *name, long long offset, long long length); From 15c60a508ab3393e68b7ccb3528981ccacf9c0f9 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 23 Jun 2011 15:33:15 +0400 Subject: [PATCH 0284/1596] mtd: drop mtd_device_register mtd_device_register() is a limited version of mtd_device_parse_register. Replace it with macro calling mtd_device_parse_register(). Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdcore.c | 23 ----------------------- include/linux/mtd/mtd.h | 5 ++--- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e18639980f7a..f9cc2d2cb5cb 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -428,29 +428,6 @@ int del_mtd_device(struct mtd_info *mtd) return ret; } -/** - * mtd_device_register - register an MTD device. - * - * @master: the MTD device to register - * @parts: the partitions to register - only valid if nr_parts > 0 - * @nr_parts: the number of partitions in parts. If zero then the full MTD - * device is registered - * - * Register an MTD device with the system and optionally, a number of - * partitions. If nr_parts is 0 then the whole device is registered, otherwise - * only the partitions are registered. To register both the full device *and* - * the partitions, call mtd_device_register() twice, once with nr_parts == 0 - * and once equal to the number of partitions. - */ -int mtd_device_register(struct mtd_info *master, - const struct mtd_partition *parts, - int nr_parts) -{ - return parts ? add_mtd_partitions(master, parts, nr_parts) : - add_mtd_device(master); -} -EXPORT_SYMBOL_GPL(mtd_device_register); - /** * mtd_device_parse_register - parse partitions and register an MTD device. * diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index b2b454b45cb5..67774f9d57cc 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -325,14 +325,13 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd) struct mtd_partition; struct mtd_part_parser_data; -extern int mtd_device_register(struct mtd_info *master, - const struct mtd_partition *parts, - int nr_parts); extern int mtd_device_parse_register(struct mtd_info *mtd, const char **part_probe_types, struct mtd_part_parser_data *parser_data, const struct mtd_partition *defparts, int defnr_parts); +#define mtd_device_register(master, parts, nr_parts) \ + mtd_device_parse_register(master, NULL, NULL, parts, nr_parts) extern int mtd_device_unregister(struct mtd_info *master); extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); extern int __get_mtd_device(struct mtd_info *mtd); From 7854d3f7495b11be1570cd3e2318674d8f9ed797 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 23 Jun 2011 14:12:08 -0700 Subject: [PATCH 0285/1596] mtd: spelling, capitalization, uniformity Therefor -> Therefore [Intern], [Internal] -> [INTERN] [REPLACABLE] -> [REPLACEABLE] syndrom, syndom -> syndrome ecc -> ECC buswith -> buswidth endianess -> endianness dont -> don't occures -> occurs independend -> independent wihin -> within erease -> erase blockes -> blocks ... Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/chips/jedec_probe.c | 2 +- drivers/mtd/devices/doc2000.c | 2 +- drivers/mtd/devices/doc2001.c | 2 +- drivers/mtd/devices/doc2001plus.c | 2 +- drivers/mtd/devices/docecc.c | 2 +- drivers/mtd/mtdchar.c | 6 +- drivers/mtd/nand/au1550nd.c | 29 ++++---- drivers/mtd/nand/cafe_nand.c | 2 +- drivers/mtd/nand/diskonchip.c | 4 +- drivers/mtd/nand/nand_base.c | 105 ++++++++++++++--------------- drivers/mtd/nand/nand_bbt.c | 8 +-- drivers/mtd/nand/nand_ecc.c | 10 +-- drivers/mtd/nand/rtc_from4.c | 2 +- drivers/mtd/onenand/onenand_base.c | 12 ++-- drivers/mtd/sm_ftl.c | 2 +- include/linux/mtd/mtd.h | 2 +- include/linux/mtd/nand.h | 50 +++++++------- 17 files changed, 119 insertions(+), 123 deletions(-) diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index ea832ea0e4aa..d40c410a3241 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1914,7 +1914,7 @@ static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi) * (oh and incidentaly the jedec spec - 3.5.3.3) the reset * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips - * as they will ignore the writes and dont care what address + * as they will ignore the writes and don't care what address * the F0 is written to */ if (cfi->addr_unlock1) { DEBUG( MTD_DEBUG_LEVEL3, diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index f7fbf6025ef2..ed15447c392e 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -699,7 +699,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) { diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 241192f05bc8..c6ea8604a3c3 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -464,7 +464,7 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC logic. + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) { syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i); diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 09ae0adc3ad0..fe82fbfa155e 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -655,7 +655,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC logic. + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index 37ef29a73ee4..4a1c39b6f37d 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -2,7 +2,7 @@ * ECC algorithm for M-systems disk on chip. We use the excellent Reed * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the * GNU GPL License. The rest is simply to convert the disk on chip - * syndrom into a standard syndom. + * syndrome into a standard syndome. * * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 49e20a497084..c60067b1f07a 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -233,9 +233,9 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t default: ret = mtd->read(mtd, *ppos, len, &retlen, kbuf); } - /* Nand returns -EBADMSG on ecc errors, but it returns + /* Nand returns -EBADMSG on ECC errors, but it returns * the data. For our userspace tools it is important - * to dump areas with ecc errors ! + * to dump areas with ECC errors! * For kernel internal usage it also might return -EUCLEAN * to signal the caller that a bitflip has occurred and has * been corrected by the ECC algorithm. @@ -883,7 +883,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) } #endif - /* This ioctl is being deprecated - it truncates the ecc layout */ + /* This ioctl is being deprecated - it truncates the ECC layout */ case ECCGETLAYOUT: { struct nand_ecclayout_user *usrlay; diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index e7767eef4505..60d58d3f1fcc 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -48,7 +48,7 @@ static const struct mtd_partition partition_info[] = { * au_read_byte - read one byte from the chip * @mtd: MTD device structure * - * read function for 8bit buswith + * read function for 8bit buswidth */ static u_char au_read_byte(struct mtd_info *mtd) { @@ -63,7 +63,7 @@ static u_char au_read_byte(struct mtd_info *mtd) * @mtd: MTD device structure * @byte: pointer to data byte to write * - * write function for 8it buswith + * write function for 8it buswidth */ static void au_write_byte(struct mtd_info *mtd, u_char byte) { @@ -73,11 +73,10 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte) } /** - * au_read_byte16 - read one byte endianess aware from the chip + * au_read_byte16 - read one byte endianness aware from the chip * @mtd: MTD device structure * - * read function for 16bit buswith with - * endianess conversion + * read function for 16bit buswidth with endianness conversion */ static u_char au_read_byte16(struct mtd_info *mtd) { @@ -88,12 +87,11 @@ static u_char au_read_byte16(struct mtd_info *mtd) } /** - * au_write_byte16 - write one byte endianess aware to the chip + * au_write_byte16 - write one byte endianness aware to the chip * @mtd: MTD device structure * @byte: pointer to data byte to write * - * write function for 16bit buswith with - * endianess conversion + * write function for 16bit buswidth with endianness conversion */ static void au_write_byte16(struct mtd_info *mtd, u_char byte) { @@ -106,8 +104,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte) * au_read_word - read one word from the chip * @mtd: MTD device structure * - * read function for 16bit buswith without - * endianess conversion + * read function for 16bit buswidth without endianness conversion */ static u16 au_read_word(struct mtd_info *mtd) { @@ -123,7 +120,7 @@ static u16 au_read_word(struct mtd_info *mtd) * @buf: data buffer * @len: number of bytes to write * - * write function for 8bit buswith + * write function for 8bit buswidth */ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { @@ -142,7 +139,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) * @buf: buffer to store date * @len: number of bytes to read * - * read function for 8bit buswith + * read function for 8bit buswidth */ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) { @@ -161,7 +158,7 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) * @buf: buffer containing the data to compare * @len: number of bytes to compare * - * verify function for 8bit buswith + * verify function for 8bit buswidth */ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { @@ -183,7 +180,7 @@ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) * @buf: data buffer * @len: number of bytes to write * - * write function for 16bit buswith + * write function for 16bit buswidth */ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) { @@ -205,7 +202,7 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) * @buf: buffer to store date * @len: number of bytes to read * - * read function for 16bit buswith + * read function for 16bit buswidth */ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) { @@ -226,7 +223,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) * @buf: buffer containing the data to compare * @len: number of bytes to compare * - * verify function for 16bit buswith + * verify function for 16bit buswidth */ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) { diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index f6eb66432c81..11a56df89eab 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -370,7 +370,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, return 1; } /** - * cafe_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read + * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index b657d7f9b05c..de93a989aa54 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -132,7 +132,7 @@ static struct rs_control *rs_decoder; /* * The HW decoder in the DoC ASIC's provides us a error syndrome, - * which we must convert to a standard syndrom usable by the generic + * which we must convert to a standard syndrome usable by the generic * Reed-Solomon library code. * * Fabrice Bellard figured this out in the old docecc code. I added @@ -153,7 +153,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc) ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2); parity = ecc[1]; - /* Initialize the syndrom buffer */ + /* Initialize the syndrome buffer */ for (i = 0; i < NROOTS; i++) s[i] = ds[0]; /* diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 408e1d0abfd1..237d7daa189c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -21,7 +21,7 @@ * TODO: * Enable cached programming for 2k page size chips * Check, if mtd->ecctype should be set to MTD_ECC_HW - * if we have HW ecc support. + * if we have HW ECC support. * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * BBT table is not serialized, has to be fixed @@ -159,7 +159,7 @@ static void nand_release_device(struct mtd_info *mtd) * nand_read_byte - [DEFAULT] read one byte from the chip * @mtd: MTD device structure * - * Default read function for 8bit buswith. + * Default read function for 8bit buswidth */ static uint8_t nand_read_byte(struct mtd_info *mtd) { @@ -169,9 +169,11 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) /** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith with endianess conversion. + * Default read function for 16bit buswidth with endianness conversion. + * */ static uint8_t nand_read_byte16(struct mtd_info *mtd) { @@ -183,7 +185,7 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) * nand_read_word - [DEFAULT] read one word from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith without endianess conversion. + * Default read function for 16bit buswidth without endianness conversion. */ static u16 nand_read_word(struct mtd_info *mtd) { @@ -220,7 +222,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) * @buf: data buffer * @len: number of bytes to write * - * Default write function for 8bit buswith. + * Default write function for 8bit buswidth. */ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -237,7 +239,7 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) * @buf: buffer to store date * @len: number of bytes to read * - * Default read function for 8bit buswith. + * Default read function for 8bit buswidth. */ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -254,7 +256,7 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) * @buf: buffer containing the data to compare * @len: number of bytes to compare * - * Default verify function for 8bit buswith. + * Default verify function for 8bit buswidth. */ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -273,7 +275,7 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) * @buf: data buffer * @len: number of bytes to write * - * Default write function for 16bit buswith. + * Default write function for 16bit buswidth. */ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -293,7 +295,7 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) * @buf: buffer to store date * @len: number of bytes to read * - * Default read function for 16bit buswith. + * Default read function for 16bit buswidth. */ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -312,7 +314,7 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) * @buf: buffer containing the data to compare * @len: number of bytes to compare * - * Default verify function for 16bit buswith. + * Default verify function for 16bit buswidth. */ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -499,7 +501,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) } } -/* Wait for the ready pin, after a command. The timeout is catched later */ +/* Wait for the ready pin, after a command. The timeout is caught later. */ void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; @@ -510,7 +512,7 @@ void nand_wait_ready(struct mtd_info *mtd) return panic_nand_wait_ready(mtd, 400); led_trigger_event(nand_led_trigger, LED_FULL); - /* Wait until command is processed or timeout occures */ + /* Wait until command is processed or timeout occurs */ do { if (chip->dev_ready(mtd)) break; @@ -629,8 +631,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page - * devices We dont have the separate regions as we have in the small page - * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. */ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -754,7 +756,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, static void panic_nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) { - /* Hardware controller shared among independend devices */ + /* Hardware controller shared among independent devices */ chip->controller->active = chip; chip->state = new_state; } @@ -1032,14 +1034,13 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) EXPORT_SYMBOL(nand_lock); /** - * nand_read_page_raw - [Intern] read raw page data without ecc + * nand_read_page_raw - [INTERN] read raw page data without ecc * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @page: page number to read * - * Not for syndrome calculating ecc controllers, which use a special oob - * layout. + * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1050,7 +1051,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc + * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -1093,7 +1094,7 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, } /** - * nand_read_page_swecc - [REPLACABLE] software ecc based page read function + * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -1134,7 +1135,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function + * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function * @mtd: mtd info structure * @chip: nand chip info structure * @data_offs: offset of requested data within the page @@ -1152,7 +1153,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; int index = 0; - /* Column address wihin the page aligned to ECC size (256bytes) */ + /* Column address within the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size; end_step = (data_offs + readlen - 1) / chip->ecc.size; num_steps = end_step - start_step + 1; @@ -1175,7 +1176,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, /* * The performance is faster if we position offsets according to - * ecc.pos. Let's make sure that there are no gaps in ecc positions. + * ecc.pos. Let's make sure that there are no gaps in ECC positions. */ for (i = 0; i < eccfrag_len - 1; i++) { if (eccpos[i + start_step * chip->ecc.bytes] + 1 != @@ -1189,7 +1190,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); } else { /* - * Send the command to read the particular ecc bytes take care + * Send the command to read the particular ECC bytes take care * about buswidth alignment in read_buf. */ index = start_step * chip->ecc.bytes; @@ -1224,14 +1225,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function + * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @page: page number to read * - * Not for syndrome calculating ecc controllers which need a special oob - * layout. + * Not for syndrome calculating ECC controllers which need a special oob layout. */ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1270,7 +1270,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first + * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -1318,7 +1318,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, } /** - * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read + * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -1373,7 +1373,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_transfer_oob - [Internal] Transfer oob to client buffer + * nand_transfer_oob - [INTERN] Transfer oob to client buffer * @chip: nand chip structure * @oob: oob destination address * @ops: oob ops structure @@ -1421,7 +1421,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, } /** - * nand_do_read_ops - [Internal] Read data with ECC + * nand_do_read_ops - [INTERN] Read data with ECC * @mtd: MTD device structure * @from: offset to read from * @ops: oob ops structure @@ -1599,7 +1599,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, } /** - * nand_read_oob_std - [REPLACABLE] the most common OOB data read function + * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to read @@ -1617,7 +1617,7 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC + * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC * with syndromes * @mtd: mtd info structure * @chip: nand chip info structure @@ -1656,7 +1656,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_oob_std - [REPLACABLE] the most common OOB data write function + * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to write @@ -1679,7 +1679,7 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC + * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC * with syndrome - only for large page flash * @mtd: mtd info structure * @chip: nand chip info structure @@ -1738,7 +1738,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, } /** - * nand_do_read_oob - [Intern] NAND read out-of-band + * nand_do_read_oob - [INTERN] NAND read out-of-band * @mtd: MTD device structure * @from: offset to read from * @ops: oob operations description structure @@ -1878,13 +1878,12 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, /** - * nand_write_page_raw - [Intern] raw page write function + * nand_write_page_raw - [INTERN] raw page write function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * - * Not for syndrome calculating ecc controllers, which use a special oob - * layout. + * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1894,7 +1893,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_raw_syndrome - [Intern] raw page write function + * nand_write_page_raw_syndrome - [INTERN] raw page write function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1933,7 +1932,7 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, chip->write_buf(mtd, oob, size); } /** - * nand_write_page_swecc - [REPLACABLE] software ecc based page write function + * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1948,7 +1947,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; - /* Software ecc calculation */ + /* Software ECC calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -1959,7 +1958,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function + * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -1987,7 +1986,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write + * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer @@ -2052,7 +2051,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, chip->ecc.write_page(mtd, chip, buf); /* - * Cached progamming disabled for now, Not sure if its worth the + * Cached progamming disabled for now. Not sure if it's worth the * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s). */ cached = 0; @@ -2087,7 +2086,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_fill_oob - [Internal] Transfer client buffer to oob + * nand_fill_oob - [INTERN] Transfer client buffer to oob * @mtd: MTD device structure * @oob: oob data buffer * @len: oob data write length @@ -2145,7 +2144,7 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) /** - * nand_do_write_ops - [Internal] NAND write with ECC + * nand_do_write_ops - [INTERN] NAND write with ECC * @mtd: MTD device structure * @to: offset to write to * @ops: oob operations description structure @@ -2454,7 +2453,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, } /** - * single_erease_cmd - [GENERIC] NAND standard block erase command function + * single_erase_cmd - [GENERIC] NAND standard block erase command function * @mtd: MTD device structure * @page: the page address of the block which will be erased * @@ -2469,7 +2468,7 @@ static void single_erase_cmd(struct mtd_info *mtd, int page) } /** - * multi_erease_cmd - [GENERIC] AND specific block erase command function + * multi_erase_cmd - [GENERIC] AND specific block erase command function * @mtd: MTD device structure * @page: the page address of the block which will be erased * @@ -2500,7 +2499,7 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) #define BBT_PAGE_MASK 0xffffff3f /** - * nand_erase_nand - [Internal] erase block(s) + * nand_erase_nand - [INTERN] erase block(s) * @mtd: MTD device structure * @instr: erase instruction * @allowbbt: allow erasing the bbt area @@ -2550,7 +2549,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, * If BBT requires refresh, set the BBT page mask to see if the BBT * should be rewritten. Otherwise the mask is set to 0xffffffff which * can not be matched. This is also done when the bbt is actually - * erased to avoid recusrsive updates. + * erased to avoid recursive updates. */ if (chip->options & BBT_AUTO_REFRESH && !allowbbt) bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; @@ -2824,7 +2823,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int i; int val; - /* Try ONFI for unknow chip or LP */ + /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') @@ -3395,7 +3394,7 @@ int nand_scan_tail(struct mtd_info *mtd) */ chip->ecc.steps = mtd->writesize / chip->ecc.size; if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { - printk(KERN_WARNING "Invalid ecc parameters\n"); + printk(KERN_WARNING "Invalid ECC parameters\n"); BUG(); } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 8875d6db2455..f30807c3a48d 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -149,7 +149,7 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) * add_marker_len - compute the length of the marker in data area * @td: BBT descriptor used for computation * - * The length will be 0 if the markeris located in OOB area. + * The length will be 0 if the marker is located in OOB area. */ static u32 add_marker_len(struct nand_bbt_descr *td) { @@ -170,7 +170,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td) * @buf: temporary buffer * @page: the starting page * @num: the number of bbt descriptors to read - * @td: the bbt describtion table + * @td: the bbt describtion table * @offs: offset in the memory table * * Read the bad block table starting from page. @@ -1241,7 +1241,7 @@ static struct nand_bbt_descr agand_flashbased = { .pattern = scan_agand_pattern }; -/* Generic flash bbt decriptors */ +/* Generic flash bbt descriptors */ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; @@ -1286,7 +1286,7 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { }; /** - * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure + * nand_create_default_bbt_descr - [INTERN] Creates a BBT descriptor structure * @this: NAND chip to create descriptor for * * This function allocates and initializes a nand_bbt_descr for BBM detection diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 271b8e735e8f..b7cfe0d37121 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -110,7 +110,7 @@ static const char bitsperbyte[256] = { /* * addressbits is a lookup table to filter out the bits from the xor-ed - * ecc data that identify the faulty location. + * ECC data that identify the faulty location. * this is only used for repairing parity * see the comments in nand_correct_data for more details */ @@ -153,7 +153,7 @@ static const char addressbits[256] = { * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte * block * @buf: input buffer with raw data - * @eccsize: data bytes per ecc step (256 or 512) + * @eccsize: data bytes per ECC step (256 or 512) * @code: output buffer with ECC */ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, @@ -348,7 +348,7 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, rp17 = (par ^ rp16) & 0xff; /* - * Finally calculate the ecc bits. + * Finally calculate the ECC bits. * Again here it might seem that there are performance optimisations * possible, but benchmarks showed that on the system this is developed * the code below is the fastest @@ -436,7 +436,7 @@ EXPORT_SYMBOL(nand_calculate_ecc); * @buf: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data - * @eccsize: data bytes per ecc step (256 or 512) + * @eccsize: data bytes per ECC step (256 or 512) * * Detect and correct a 1 bit error for eccsize byte block */ @@ -505,7 +505,7 @@ int __nand_correct_data(unsigned char *buf, } /* count nr of bits; use table lookup, faster than calculating it */ if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) - return 1; /* error in ecc data; no action needed */ + return 1; /* error in ECC data; no action needed */ printk(KERN_ERR "uncorrectable error : "); return -1; diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index a07da2a3beee..33fe922b972c 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -351,7 +351,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha return 0; } - /* Read the syndrom pattern from the FPGA and correct the bitorder */ + /* Read the syndrome pattern from the FPGA and correct the bitorder */ rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC); for (i = 0; i < 8; i++) { ecc[i] = bitrev8(*rs_ecc); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 51800a7ef7f8..30c652c071e8 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1015,7 +1015,7 @@ static void onenand_release_device(struct mtd_info *mtd) } /** - * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer * @param mtd MTD device structure * @param buf destination address * @param column oob offset to read from @@ -1821,7 +1821,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, } /** - * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer * @param mtd MTD device structure * @param oob_buf oob buffer * @param buf source address @@ -2055,7 +2055,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, /** - * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band + * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -2281,7 +2281,7 @@ static int onenand_multiblock_erase_verify(struct mtd_info *mtd, } /** - * onenand_multiblock_erase - [Internal] erase block(s) using multiblock erase + * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase * @param mtd MTD device structure * @param instr erase instruction * @param region erase region @@ -2397,7 +2397,7 @@ static int onenand_multiblock_erase(struct mtd_info *mtd, /** - * onenand_block_by_block_erase - [Internal] erase block(s) using regular erase + * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase * @param mtd MTD device structure * @param instr erase instruction * @param region erase region @@ -2922,7 +2922,7 @@ static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr, } /** - * onenand_otp_write_oob_nolock - [Internal] OneNAND write out-of-band, specific to OTP + * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index ed3d6cd2c6dc..a8befde81ce9 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -138,7 +138,7 @@ static int sm_get_lba(uint8_t *lba) if ((lba[0] & 0xF8) != 0x10) return -2; - /* check parity - endianess doesn't matter */ + /* check parity - endianness doesn't matter */ if (hweight16(*(uint16_t *)lba) & 1) return -2; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 67774f9d57cc..62d56f933b87 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -172,7 +172,7 @@ struct mtd_info { const char *name; int index; - /* ecc layout structure pointer - read only ! */ + /* ECC layout structure pointer - read only! */ struct nand_ecclayout *ecclayout; /* Data for variable erase regions. If numeraseregions is zero, diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 0f239e714219..877fbbda02cd 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -42,10 +42,10 @@ extern void nand_release(struct mtd_info *mtd); /* Internal helper for board drivers which need to override command function */ extern void nand_wait_ready(struct mtd_info *mtd); -/* locks all blockes present in the device */ +/* locks all blocks present in the device */ extern int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); -/* unlocks specified locked blockes */ +/* unlocks specified locked blocks */ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); /* The maximum number of NAND chips in an array */ @@ -150,7 +150,7 @@ typedef enum { #define NAND_ECC_READ 0 /* Reset Hardware ECC for write */ #define NAND_ECC_WRITE 1 -/* Enable Hardware ECC before syndrom is read back from flash */ +/* Enable Hardware ECC before syndrome is read back from flash */ #define NAND_ECC_READSYN 2 /* Bit mask for flags passed to do_nand_read_ecc */ @@ -163,7 +163,7 @@ typedef enum { */ /* Chip can not auto increment pages */ #define NAND_NO_AUTOINCR 0x00000001 -/* Buswitdh is 16 bit */ +/* Buswidth is 16 bit */ #define NAND_BUSWIDTH_16 0x00000002 /* Device supports partial programming without padding */ #define NAND_NO_PADDING 0x00000004 @@ -319,26 +319,26 @@ struct nand_hw_control { }; /** - * struct nand_ecc_ctrl - Control structure for ecc - * @mode: ecc mode - * @steps: number of ecc steps per page - * @size: data bytes per ecc step - * @bytes: ecc bytes per step - * @total: total number of ecc bytes per page - * @prepad: padding information for syndrome based ecc generators - * @postpad: padding information for syndrome based ecc generators + * struct nand_ecc_ctrl - Control structure for ECC + * @mode: ECC mode + * @steps: number of ECC steps per page + * @size: data bytes per ECC step + * @bytes: ECC bytes per step + * @total: total number of ECC bytes per page + * @prepad: padding information for syndrome based ECC generators + * @postpad: padding information for syndrome based ECC generators * @layout: ECC layout control struct pointer - * @priv: pointer to private ecc control data - * @hwctl: function to control hardware ecc generator. Must only + * @priv: pointer to private ECC control data + * @hwctl: function to control hardware ECC generator. Must only * be provided if an hardware ECC is available - * @calculate: function for ecc calculation or readback from ecc hardware - * @correct: function for ecc correction, matching to ecc generator (sw/hw) + * @calculate: function for ECC calculation or readback from ECC hardware + * @correct: function for ECC correction, matching to ECC generator (sw/hw) * @read_page_raw: function to read a raw page without ECC * @write_page_raw: function to write a raw page without ECC - * @read_page: function to read a page according to the ecc generator + * @read_page: function to read a page according to the ECC generator * requirements. * @read_subpage: function to read parts of the page covered by ECC. - * @write_page: function to write a page according to the ecc generator + * @write_page: function to write a page according to the ECC generator * requirements. * @read_oob: function to read chip OOB data * @write_oob: function to write chip OOB data @@ -376,8 +376,8 @@ struct nand_ecc_ctrl { /** * struct nand_buffers - buffer structure for read/write - * @ecccalc: buffer for calculated ecc - * @ecccode: buffer for ecc read from flash + * @ecccalc: buffer for calculated ECC + * @ecccode: buffer for ECC read from flash * @databuf: buffer for data - dynamically sized * * Do not change the order of buffers. databuf and oobrbuf must be in @@ -410,7 +410,7 @@ struct nand_buffers { * mtd->oobsize, mtd->writesize and so on. * @id_data contains the 8 bytes values of NAND_CMD_READID. * Return with the bus width. - * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing + * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accessing * device ready/busy line. If set to NULL no access to * ready/busy is available and the ready/busy information * is read from the chip status register. @@ -418,7 +418,7 @@ struct nand_buffers { * commands to the chip. * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on * ready. - * @ecc: [BOARDSPECIFIC] ecc control ctructure + * @ecc: [BOARDSPECIFIC] ECC control structure * @buffers: buffer structure for read/write * @hwcontrol: platform-specific hardware control structure * @ops: oob operation operands @@ -455,7 +455,7 @@ struct nand_buffers { * non 0 if ONFI supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * supported, 0 otherwise. - * @ecclayout: [REPLACEABLE] the default ecc placement scheme + * @ecclayout: [REPLACEABLE] the default ECC placement scheme * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash * lookup. @@ -463,7 +463,7 @@ struct nand_buffers { * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial * bad block scan. * @controller: [REPLACEABLE] a pointer to a hardware controller - * structure which is shared among multiple independend + * structure which is shared among multiple independent * devices. * @priv: [OPTIONAL] pointer to private chip date * @errstat: [OPTIONAL] hardware specific function to perform @@ -604,7 +604,7 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, * @chip_delay: R/B delay value in us * @options: Option flags, e.g. 16bit buswidth * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH - * @ecclayout: ecc layout info structure + * @ecclayout: ECC layout info structure * @part_probe_types: NULL-terminated array of probe types * @set_parts: platform specific function to set partitions * @priv: hardware controller specific settings From d6137badeff1ef64b4e0092ec249ebdeaeb3ff37 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 27 Jun 2011 01:02:59 +0400 Subject: [PATCH 0286/1596] mtd: make ofpart buildable as a separate module As ofpart now uses a standard mtd partitions parser interface, make it buildable as a separate module. Also provide MODULE_DESCRIPTION and MODULE_AUTHOR for this module. Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Randy Dunlap Signed-off-by: Artem Bityutskiy --- drivers/mtd/Kconfig | 3 ++- drivers/mtd/Makefile | 2 +- drivers/mtd/ofpart.c | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 4be8373d43e5..cc02e2115efb 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -137,7 +137,8 @@ config MTD_AFS_PARTS 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. config MTD_OF_PARTS - def_bool y + tristate "OpenFirmware partitioning information support" + default Y depends on OF help This provides a partition parsing function which derives diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 39664c4229ff..9aaac3ac89f3 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -5,8 +5,8 @@ # Core functionality. obj-$(CONFIG_MTD) += mtd.o mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o -mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o +obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 41c451842fd2..aa33b8ad4f3c 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -174,3 +174,5 @@ static int __init ofpart_parser_init(void) module_init(ofpart_parser_init); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); +MODULE_AUTHOR("Vitaly Wool, David Gibson"); From 041e4575f03400e045f00a823fcbbbb337de8409 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 23 Jun 2011 16:45:24 -0700 Subject: [PATCH 0287/1596] mtd: nand: handle ECC errors in OOB While the standard NAND OOB functions do not do ECC on the spare area, it is possible for a driver to supply its own OOB ECC functions (e.g., HW ECC). nand_do_read_oob should act like nand_do_read_ops in checking the ECC stats and returning -EBADMSG or -EUCLEAN on uncorrectable errors or correctable bitflips, respectively. These error codes could be used in flash-based BBT code or in YAFFS, for example. Doing this, however, messes with the behavior of mtd_do_readoob. Now, mtd_do_readoob should check whether we had -EUCLEAN or -EBADMSG errors and discard those as "non-fatal" so that the ioctls can still succeed with (possibly uncorrected) data. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 15 +++++++++++++++ drivers/mtd/nand/nand_base.c | 9 ++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index c60067b1f07a..d5924635ead5 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -473,6 +473,21 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, ret = -EFAULT; kfree(ops.oobbuf); + + /* + * NAND returns -EBADMSG on ECC errors, but it returns the OOB + * data. For our userspace tools it is important to dump areas + * with ECC errors! + * For kernel internal usage it also might return -EUCLEAN + * to signal the caller that a bitflip has occured and has + * been corrected by the ECC algorithm. + * + * Note: most NAND ECC algorithms do not calculate ECC + * for the OOB area. + */ + if (ret == -EUCLEAN || ret == -EBADMSG) + return 0; + return ret; } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 237d7daa189c..5418d27122c4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1750,6 +1750,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, { int page, realpage, chipnr, sndcmd = 1; struct nand_chip *chip = mtd->priv; + struct mtd_ecc_stats stats; int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; int readlen = ops->ooblen; int len; @@ -1758,6 +1759,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); + stats = mtd->ecc_stats; + if (ops->mode == MTD_OOB_AUTO) len = chip->ecc.layout->oobavail; else @@ -1828,7 +1831,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, } ops->oobretlen = ops->ooblen; - return 0; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** From 9786f6e68af00d0988ad7f51fe3fd118be1c30ad Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 27 Jun 2011 16:34:46 +0400 Subject: [PATCH 0288/1596] mtd: ofpart: add ofoldpart alias ofpart.ko also provides ofoldpart MTD parser. Add respective MODULE_ALIAS("ofoldpart"); declaration. Artem: improve the comment Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Artem Bityutskiy --- drivers/mtd/ofpart.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index aa33b8ad4f3c..64be8f0848b0 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -176,3 +176,9 @@ module_init(ofpart_parser_init); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); MODULE_AUTHOR("Vitaly Wool, David Gibson"); +/* + * When MTD core cannot find the requested parser, it tries to load the module + * with the same name. Since we provide the ofoldpart parser, we should have + * the corresponding alias. + */ +MODULE_ALIAS("ofoldpart"); From 51b11e3630672b7ce8793ecf13e5759656edf38a Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Tue, 28 Jun 2011 00:21:30 +0400 Subject: [PATCH 0289/1596] jffs2: use mutex_is_locked() in __jffs2_flush_wbuf() Use a helper to test if a mutex is held instead of a hack with mutex_trylock(). Signed-off-by: Alexey Khoroshilov Signed-off-by: Artem Bityutskiy --- fs/jffs2/wbuf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 4515bea0268f..a10fb24ca6e6 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -578,8 +578,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) if (!jffs2_is_writebuffered(c)) return 0; - if (mutex_trylock(&c->alloc_sem)) { - mutex_unlock(&c->alloc_sem); + if (!mutex_is_locked(&c->alloc_sem)) { printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n"); BUG(); } From 903cd06cd6ece7f9050a3ad5b03e0b76be2882ff Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 28 Jun 2011 16:28:58 -0700 Subject: [PATCH 0290/1596] mtd: nand: ignore ECC errors for simple BBM scans Now that nand_do_readoob() may return -EUCLEAN or -EBADMSG on ECC errors, we need to handle the return value specially in some cases. When scanning for simple bad block markers, reacting to an ECC error is not very useful, as we assume that the relevant markers are still non-0xFF for true bad blocks. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index f30807c3a48d..a4fcbf1cbc76 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -312,14 +312,20 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, ops.oobbuf = buf + len; ops.datbuf = buf; ops.len = len; - return mtd->read_oob(mtd, offs, &ops); + res = mtd->read_oob(mtd, offs, &ops); + + /* Ignore ECC errors when checking for BBM */ + if (res != -EUCLEAN && res != -EBADMSG) + return res; + return 0; } else { ops.oobbuf = buf + mtd->writesize; ops.datbuf = buf; ops.len = mtd->writesize; res = mtd->read_oob(mtd, offs, &ops); - if (res) + /* Ignore ECC errors when checking for BBM */ + if (res && res != -EUCLEAN && res != -EBADMSG) return res; } @@ -435,7 +441,8 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, * byte reads for 16 bit buswidth. */ ret = mtd->read_oob(mtd, offs, &ops); - if (ret) + /* Ignore ECC errors when checking for BBM */ + if (ret && ret != -EUCLEAN && ret != -EBADMSG) return ret; if (check_short_pattern(buf, bd)) From 003bc47922047e21ebfb19cb99317273b313f79d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 28 Jun 2011 16:28:59 -0700 Subject: [PATCH 0291/1596] mtd: tests: ignore corrected bitflips in OOB on mtd_readtest read_oob may now return ECC error codes. If the code is -EUCLEAN, then we can safely ignore the error as a corrected bitflip. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/tests/mtd_readtest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index afe71aa15c4b..836792d1d60e 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -75,7 +75,8 @@ static int read_eraseblock_by_page(int ebnum) ops.datbuf = NULL; ops.oobbuf = oobbuf; ret = mtd->read_oob(mtd, addr, &ops); - if (ret || ops.oobretlen != mtd->oobsize) { + if ((ret && ret != -EUCLEAN) || + ops.oobretlen != mtd->oobsize) { printk(PRINT_PREF "error: read oob failed at " "%#llx\n", (long long)addr); if (!err) From c478d7e449508d924628b012e62dee6dddb6b9e9 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 28 Jun 2011 16:29:00 -0700 Subject: [PATCH 0292/1596] mtd: edit NAND-related comment This comment was unclear regarding which NAND functions do and do not support ECC on the spare area. This update should reflect the current status of the NAND system but can be updated if changes are made in the standard functions. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d5924635ead5..e197192331f9 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -482,8 +482,9 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, * to signal the caller that a bitflip has occured and has * been corrected by the ECC algorithm. * - * Note: most NAND ECC algorithms do not calculate ECC - * for the OOB area. + * Note: currently the standard NAND function, nand_read_oob_std, + * does not calculate ECC for the OOB area, so do not rely on + * this behavior unless you have replaced it with your own. */ if (ret == -EUCLEAN || ret == -EBADMSG) return 0; From 08c248fbe2bfc0326255c5b0cb3952166234d59b Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Sun, 26 Jun 2011 18:26:55 +0200 Subject: [PATCH 0293/1596] mtd: nand_flash_detect_onfi propagate busw info there is a bug in nand_flash_detect_onfi, busw need to be passed by pointer to return it. Signed-off-by: Matthieu CASTET Acked-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5418d27122c4..250e86f5592e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2824,7 +2824,7 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, - int busw) + int *busw) { struct nand_onfi_params *p = &chip->onfi_params; int i; @@ -2879,9 +2879,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; - busw = 0; + *busw = 0; if (le16_to_cpu(p->features) & 1) - busw = NAND_BUSWIDTH_16; + *busw = NAND_BUSWIDTH_16; chip->options &= ~NAND_CHIPOPTIONS_MSK; chip->options |= (NAND_NO_READRDY | @@ -2948,7 +2948,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->onfi_version = 0; if (!type->name || !type->pagesize) { /* Check is chip is ONFI compliant */ - ret = nand_flash_detect_onfi(mtd, chip, busw); + ret = nand_flash_detect_onfi(mtd, chip, &busw); if (ret) goto ident_done; } From 201ab536ac205a2787f8eac2eedc697616f99e04 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 29 Jun 2011 18:41:16 +0200 Subject: [PATCH 0294/1596] mtd: atmel_nand: fix wrong use of 0 as NULL Fixing this error: atmel_nand.c:718:20: warning: Using plain integer as NULL pointer Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/atmel_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index b1381437a957..ee6e26e78a1a 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -588,7 +588,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) dma_cap_zero(mask); dma_cap_set(DMA_MEMCPY, mask); - host->dma_chan = dma_request_channel(mask, 0, NULL); + host->dma_chan = dma_request_channel(mask, NULL, NULL); if (!host->dma_chan) { dev_err(host->dev, "Failed to request DMA channel\n"); use_dma = 0; From a751d3155dee38cb2a8e46d8cf3fa6998b2f3239 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 30 Jun 2011 19:53:09 +0800 Subject: [PATCH 0295/1596] mtd: fsl_upm: fix a memory leak in fun_chip_init error path Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_upm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index da92fed9f27b..b4f3cc9f32fb 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -196,6 +196,8 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, ret = mtd_device_parse_register(&fun->mtd, NULL, &ppdata, NULL, 0); err: of_node_put(flash_np); + if (ret) + kfree(fun->mtd.name); return ret; } From b4ca74738ab6c9ed8190b06cd7bf785dc98c640e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 1 Jul 2011 13:51:15 +0200 Subject: [PATCH 0296/1596] mtd: plat-nand: Fixup kerneldoc for struct platform_nand_chip The set_parts and priv members of struct platform_nand_chip where removed in commit c36a6ef3845262ade529afb9f458738b1f196f83 but the kerneldoc wasn't updated. Signed-off-by: Tobias Klauser Signed-off-by: Artem Bityutskiy --- include/linux/mtd/nand.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 877fbbda02cd..6d5696876b3f 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -606,8 +606,6 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH * @ecclayout: ECC layout info structure * @part_probe_types: NULL-terminated array of probe types - * @set_parts: platform specific function to set partitions - * @priv: hardware controller specific settings */ struct platform_nand_chip { int nr_chips; From 57b078a09bf0ab3f0babcfe6ecb2ac226d9178be Mon Sep 17 00:00:00 2001 From: Liu Shuo Date: Tue, 28 Jun 2011 09:50:51 +0800 Subject: [PATCH 0297/1596] mtd: nand: don't free the global data too early The global data fsl_lbc_ctrl_dev->nand don't have to be freed in fsl_elbc_chip_remove(). The right place to do that is in fsl_elbc_nand_remove() if elbc_fcm_ctrl->counter is zero. Signed-off-by: Liu Shuo Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_elbc_nand.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 915b4a4c06c2..3c2f03c55cac 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -829,7 +829,6 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) elbc_fcm_ctrl->chips[priv->bank] = NULL; kfree(priv); - kfree(elbc_fcm_ctrl); return 0; } From fb5427508abbd635e877fabdf55795488119c2d6 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 4 Jul 2011 16:17:53 +0200 Subject: [PATCH 0298/1596] mtd: atmel_nand: optimize read/write buffer functions For PIO NAND access functions, we use the features of the SMC: - no need to take into account the NAND bus width: SMC will deal with this - use of an IO memcpy on the NAND chip-select space is able to generate proper SMC behavior. Signed-off-by: Nicolas Ferre Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/atmel_nand.c | 45 ++++------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index ee6e26e78a1a..23e5d77c39fc 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -161,37 +161,6 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) !!host->board->rdy_pin_active_low; } -/* - * Minimal-overhead PIO for data access. - */ -static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_readsb(nand_chip->IO_ADDR_R, buf, len); -} - -static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); -} - -static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_writesb(nand_chip->IO_ADDR_W, buf, len); -} - -static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); -} - static void dma_complete_func(void *completion) { complete(completion); @@ -266,33 +235,27 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) { struct nand_chip *chip = mtd->priv; - struct atmel_nand_host *host = chip->priv; if (use_dma && len > mtd->oobsize) /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) return; - if (host->board->bus_width_16) - atmel_read_buf16(mtd, buf, len); - else - atmel_read_buf8(mtd, buf, len); + /* if no DMA operation possible, use PIO */ + memcpy_fromio(buf, chip->IO_ADDR_R, len); } static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { struct nand_chip *chip = mtd->priv; - struct atmel_nand_host *host = chip->priv; if (use_dma && len > mtd->oobsize) /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) return; - if (host->board->bus_width_16) - atmel_write_buf16(mtd, buf, len); - else - atmel_write_buf8(mtd, buf, len); + /* if no DMA operation possible, use PIO */ + memcpy_toio(chip->IO_ADDR_W, buf, len); } /* From 52a474de0a830bdf4305ef19c3321064ce5da438 Mon Sep 17 00:00:00 2001 From: Mike Hench Date: Tue, 5 Jul 2011 19:14:48 -0400 Subject: [PATCH 0299/1596] mtd: eLBC NAND: remove elbc_fcm_ctrl->oob_poi The eLBC NAND driver currently follows up each program/write operation with a read-back of the page, in order to [ostensibly] fill in ECC data for the caller. However, the page address used for this read is always -1, so the read will never work correctly. Remove this useless (and potentially problematic) block of code. Signed-off-by: Matthew L. Creech Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_elbc_nand.c | 33 ++------------------------------ 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 3c2f03c55cac..acc27ee04749 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -75,7 +75,6 @@ struct fsl_elbc_fcm_ctrl { unsigned int use_mdr; /* Non zero if the MDR is to be set */ unsigned int oob; /* Non zero if operating on OOB data */ unsigned int counter; /* counter for the initializations */ - char *oob_poi; /* Place to write ECC after read back */ }; /* These map to the positions used by the FCM hardware ECC generator */ @@ -435,7 +434,6 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: { - int full_page; dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " "writing %d bytes.\n", elbc_fcm_ctrl->index); @@ -445,34 +443,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, * write so the HW generates the ECC. */ if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || - elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) { + elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); - full_page = 0; - } else { + else out_be32(&lbc->fbcr, 0); - full_page = 1; - } fsl_elbc_run_command(mtd); - - /* Read back the page in order to fill in the ECC for the - * caller. Is this really needed? - */ - if (full_page && elbc_fcm_ctrl->oob_poi) { - out_be32(&lbc->fbcr, 3); - set_addr(mtd, 6, page_addr, 1); - - elbc_fcm_ctrl->read_bytes = mtd->writesize + 9; - - fsl_elbc_do_read(chip, 1); - fsl_elbc_run_command(mtd); - - memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6, - &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3); - elbc_fcm_ctrl->index += 3; - } - - elbc_fcm_ctrl->oob_poi = NULL; return; } @@ -752,13 +728,8 @@ static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; - fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - elbc_fcm_ctrl->oob_poi = chip->oob_poi; } static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) From 051fc41c2e578e10950bf34dc84878e489e0679f Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Thu, 14 Jul 2011 20:44:30 -0700 Subject: [PATCH 0300/1596] mtd: pxa3xx_nand: enhance suspend and resume routine This patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug. Signed-off-by: Lei Wen --- drivers/mtd/nand/pxa3xx_nand.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b7db1b2021f2..61e1ff5a9ada 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1158,23 +1158,36 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); + struct mtd_info *mtd = info->mtd; if (info->state) { dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); return -EAGAIN; } + mtd->suspend(mtd); return 0; } static int pxa3xx_nand_resume(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); + struct mtd_info *mtd = info->mtd; + + /* We don't want to handle interrupt without calling mtd routine */ + disable_int(info, NDCR_INT_MASK); nand_writel(info, NDTR0CS0, info->ndtr0cs0); nand_writel(info, NDTR1CS0, info->ndtr1cs0); - clk_enable(info->clk); + /* + * As the spec says, the NDSR would be updated to 0x1800 when + * doing the nand_clk disable/enable. + * To prevent it damaging state machine of the driver, clear + * all status before resume + */ + nand_writel(info, NDSR, NDSR_MASK); + mtd->resume(mtd); return 0; } #else From da675b4ef20bb460f185e0aca4afeb8c3e7e4477 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Thu, 14 Jul 2011 20:44:31 -0700 Subject: [PATCH 0301/1596] mtd: pxa3xx_nand: convert all printk into dev_* Also add missed warning message. Signed-off-by: Lei Wen Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/pxa3xx_nand.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 61e1ff5a9ada..e55d7f8df978 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -359,7 +359,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) DIV_ROUND_UP(info->oob_size, 4)); break; default: - printk(KERN_ERR "%s: invalid state %d\n", __func__, + dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -385,7 +385,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info) desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; break; default: - printk(KERN_ERR "%s: invalid state %d\n", __func__, + dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -616,8 +616,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, default: exec_cmd = 0; - printk(KERN_ERR "pxa3xx-nand: non-supported" - " command %x\n", command); + dev_err(&info->pdev->dev, "non-supported command %x\n", + command); break; } @@ -646,7 +646,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, ret = wait_for_completion_timeout(&info->cmd_complete, CHIP_DELAY_TIMEOUT); if (!ret) { - printk(KERN_ERR "Wait time out!!!\n"); + dev_err(&info->pdev->dev, "Wait time out!!!\n"); /* Stop State Machine for next command cycle */ pxa3xx_nand_stop(info); } @@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; uint32_t ndcr = 0x0; /* enable all interrupts */ - if (f->page_size != 2048 && f->page_size != 512) + if (f->page_size != 2048 && f->page_size != 512) { + dev_err(&pdev->dev, "Current only support 2048 and 512 size\n"); return -EINVAL; + } - if (f->flash_width != 16 && f->flash_width != 8) + if (f->flash_width != 16 && f->flash_width != 8) { + dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n"); return -EINVAL; + } /* calculate flash information */ info->cmdset = &default_cmdset; @@ -898,7 +902,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (!ret) { kfree(mtd); info->mtd = NULL; - printk(KERN_INFO "There is no nand chip on cs 0!\n"); + dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n"); return -EINVAL; } @@ -906,11 +910,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); id = *((uint16_t *)(info->data_buff)); if (id != 0) - printk(KERN_INFO "Detect a flash id %x\n", id); + dev_info(&info->pdev->dev, "Detect a flash id %x\n", id); else { kfree(mtd); info->mtd = NULL; - printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n"); + dev_warn(&info->pdev->dev, + "Read out ID 0, potential timing set wrong!!\n"); return -EINVAL; } @@ -930,7 +935,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { kfree(mtd); info->mtd = NULL; - printk(KERN_ERR "ERROR!! flash not defined!!!\n"); + dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n"); return -EINVAL; } From d456882b41b84eba5e729cf78757b8ed95572362 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Thu, 14 Jul 2011 20:44:32 -0700 Subject: [PATCH 0302/1596] mtd: pxa3xx_nand: sperate each chip individual info For support two chip select, we seperate chip specific info in this patch. Signed-off-by: Lei Wen --- drivers/mtd/nand/pxa3xx_nand.c | 292 ++++++++++++++++++--------------- 1 file changed, 160 insertions(+), 132 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index e55d7f8df978..97b689499119 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -110,6 +110,7 @@ enum { enum { STATE_IDLE = 0, + STATE_PREPARED, STATE_CMD_HANDLE, STATE_DMA_READING, STATE_DMA_WRITING, @@ -120,21 +121,39 @@ enum { STATE_READY, }; -struct pxa3xx_nand_info { - struct nand_chip nand_chip; +struct pxa3xx_nand_host { + struct nand_chip chip; + struct pxa3xx_nand_cmdset *cmdset; + struct mtd_info *mtd; + void *info_data; + + /* page size of attached chip */ + unsigned int page_size; + int use_ecc; + /* calculated from pxa3xx_nand_flash data */ + unsigned int col_addr_cycles; + unsigned int row_addr_cycles; + size_t read_id_bytes; + + /* cached register value */ + uint32_t reg_ndcr; + uint32_t ndtr0cs0; + uint32_t ndtr1cs0; +}; + +struct pxa3xx_nand_info { struct nand_hw_control controller; struct platform_device *pdev; - struct pxa3xx_nand_cmdset *cmdset; struct clk *clk; void __iomem *mmio_base; unsigned long mmio_phys; + struct completion cmd_complete; unsigned int buf_start; unsigned int buf_count; - struct mtd_info *mtd; /* DMA information */ int drcmr_dat; int drcmr_cmd; @@ -142,18 +161,11 @@ struct pxa3xx_nand_info { unsigned char *data_buff; unsigned char *oob_buff; dma_addr_t data_buff_phys; - size_t data_buff_size; int data_dma_ch; struct pxa_dma_desc *data_desc; dma_addr_t data_desc_addr; - uint32_t reg_ndcr; - - /* saved column/page_addr during CMD_SEQIN */ - int seqin_column; - int seqin_page_addr; - - /* relate to the command */ + struct pxa3xx_nand_host *host; unsigned int state; int use_ecc; /* use HW ECC ? */ @@ -162,24 +174,13 @@ struct pxa3xx_nand_info { unsigned int page_size; /* page size of attached chip */ unsigned int data_size; /* data size in FIFO */ + unsigned int oob_size; int retcode; - struct completion cmd_complete; /* generated NDCBx register values */ uint32_t ndcb0; uint32_t ndcb1; uint32_t ndcb2; - - /* timing calcuted from setting */ - uint32_t ndtr0cs0; - uint32_t ndtr1cs0; - - /* calculated from pxa3xx_nand_flash data */ - size_t oob_size; - size_t read_id_bytes; - - unsigned int col_addr_cycles; - unsigned int row_addr_cycles; }; static int use_dma = 1; @@ -241,9 +242,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; /* convert nano-seconds to nand flash controller clock cycles */ #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) -static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, const struct pxa3xx_nand_timing *t) { + struct pxa3xx_nand_info *info = host->info_data; unsigned long nand_clk = clk_get_rate(info->clk); uint32_t ndtr0, ndtr1; @@ -258,23 +260,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); - info->ndtr0cs0 = ndtr0; - info->ndtr1cs0 = ndtr1; + host->ndtr0cs0 = ndtr0; + host->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1); } static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { - int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; + struct pxa3xx_nand_host *host = info->host; + int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; - info->data_size = info->page_size; + info->data_size = host->page_size; if (!oob_enable) { info->oob_size = 0; return; } - switch (info->page_size) { + switch (host->page_size) { case 2048: info->oob_size = (info->use_ecc) ? 40 : 64; break; @@ -292,9 +295,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) */ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) { + struct pxa3xx_nand_host *host = info->host; uint32_t ndcr; - ndcr = info->reg_ndcr; + ndcr = host->reg_ndcr; ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; ndcr |= info->use_dma ? NDCR_DMA_EN : 0; ndcr |= NDCR_ND_RUN; @@ -463,12 +467,6 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) return IRQ_HANDLED; } -static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) -{ - struct pxa3xx_nand_info *info = mtd->priv; - return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0; -} - static inline int is_buf_blank(uint8_t *buf, size_t len) { for (; len > 0; len--) @@ -481,10 +479,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, uint16_t column, int page_addr) { uint16_t cmd; - int addr_cycle, exec_cmd, ndcb0; - struct mtd_info *mtd = info->mtd; + int addr_cycle, exec_cmd; + struct pxa3xx_nand_host *host = info->host; + struct mtd_info *mtd = host->mtd; - ndcb0 = 0; addr_cycle = 0; exec_cmd = 1; @@ -494,6 +492,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size = 0; info->use_ecc = 0; info->is_ready = 0; + info->ndcb0 = 0; info->retcode = ERR_NONE; switch (command) { @@ -512,20 +511,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; } - info->ndcb0 = ndcb0; - addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles - + info->col_addr_cycles); + addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles + + host->col_addr_cycles); switch (command) { case NAND_CMD_READOOB: case NAND_CMD_READ0: - cmd = info->cmdset->read1; + cmd = host->cmdset->read1; if (command == NAND_CMD_READOOB) info->buf_start = mtd->writesize + column; else info->buf_start = column; - if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) + if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) info->ndcb0 |= NDCB0_CMD_TYPE(0) | addr_cycle | (cmd & NDCB0_CMD1_MASK); @@ -537,7 +535,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, case NAND_CMD_SEQIN: /* small page addr setting */ - if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { + if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) { info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) | (column & 0xFF); @@ -564,7 +562,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; } - cmd = info->cmdset->program; + cmd = host->cmdset->program; info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | NDCB0_AUTO_RS | NDCB0_ST_ROW_EN @@ -574,8 +572,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_READID: - cmd = info->cmdset->read_id; - info->buf_count = info->read_id_bytes; + cmd = host->cmdset->read_id; + info->buf_count = host->read_id_bytes; info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1) | cmd; @@ -583,7 +581,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->data_size = 8; break; case NAND_CMD_STATUS: - cmd = info->cmdset->read_status; + cmd = host->cmdset->read_status; info->buf_count = 1; info->ndcb0 |= NDCB0_CMD_TYPE(4) | NDCB0_ADDR_CYC(1) @@ -593,7 +591,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_ERASE1: - cmd = info->cmdset->erase; + cmd = host->cmdset->erase; info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3) @@ -604,7 +602,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_RESET: - cmd = info->cmdset->reset; + cmd = host->cmdset->reset; info->ndcb0 |= NDCB0_CMD_TYPE(5) | cmd; @@ -627,7 +625,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int ret, exec_cmd; /* @@ -635,9 +634,10 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, * "byte" address into a "word" address appropriate * for indexing a word-oriented device */ - if (info->reg_ndcr & NDCR_DWIDTH_M) + if (host->reg_ndcr & NDCR_DWIDTH_M) column /= 2; + info->state = STATE_PREPARED; exec_cmd = prepare_command_pool(info, command, column, page_addr); if (exec_cmd) { init_completion(&info->cmd_complete); @@ -650,8 +650,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, /* Stop State Machine for next command cycle */ pxa3xx_nand_stop(info); } - info->state = STATE_IDLE; } + info->state = STATE_IDLE; } static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, @@ -664,7 +664,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -695,7 +696,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; char retval = 0xFF; if (info->buf_start < info->buf_count) @@ -707,7 +709,8 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; u16 retval = 0xFFFF; if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { @@ -719,7 +722,8 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int real_len = min_t(size_t, len, info->buf_count - info->buf_start); memcpy(buf, info->data_buff + info->buf_start, real_len); @@ -729,7 +733,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) static void pxa3xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int real_len = min_t(size_t, len, info->buf_count - info->buf_start); memcpy(info->data_buff + info->buf_start, buf, real_len); @@ -749,7 +754,8 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip) static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; /* pxa3xx_nand_send_command has waited for command complete */ if (this->state == FL_WRITING || this->state == FL_ERASING) { @@ -772,6 +778,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, { struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; + struct pxa3xx_nand_host *host = info->host; uint32_t ndcr = 0x0; /* enable all interrupts */ if (f->page_size != 2048 && f->page_size != 512) { @@ -785,45 +792,52 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, } /* calculate flash information */ - info->cmdset = &default_cmdset; - info->page_size = f->page_size; - info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; + host->cmdset = &default_cmdset; + host->page_size = f->page_size; + host->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ - info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; + host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; if (f->num_blocks * f->page_per_block > 65536) - info->row_addr_cycles = 3; + host->row_addr_cycles = 3; else - info->row_addr_cycles = 2; + host->row_addr_cycles = 2; ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0; + ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; - ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes); + ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes); ndcr |= NDCR_SPARE_EN; /* enable spare by default */ - info->reg_ndcr = ndcr; + host->reg_ndcr = ndcr; - pxa3xx_nand_set_timing(info, f->timing); + pxa3xx_nand_set_timing(host, f->timing); return 0; } static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { + struct pxa3xx_nand_host *host = info->host; uint32_t ndcr = nand_readl(info, NDCR); - info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - /* set info fields needed to read id */ - info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; - info->reg_ndcr = ndcr & ~NDCR_INT_MASK; - info->cmdset = &default_cmdset; - info->ndtr0cs0 = nand_readl(info, NDTR0CS0); - info->ndtr1cs0 = nand_readl(info, NDTR1CS0); + if (ndcr & NDCR_PAGE_SZ) { + host->page_size = 2048; + host->read_id_bytes = 4; + } else { + host->page_size = 512; + host->read_id_bytes = 2; + } + + host->reg_ndcr = ndcr & ~NDCR_INT_MASK; + host->cmdset = &default_cmdset; + + host->ndtr0cs0 = nand_readl(info, NDTR0CS0); + host->ndtr1cs0 = nand_readl(info, NDTR1CS0); return 0; } @@ -853,7 +867,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) return -ENOMEM; } - info->data_buff_size = MAX_BUFF_SIZE; info->data_desc = (void *)info->data_buff + data_desc_offset; info->data_desc_addr = info->data_buff_phys + data_desc_offset; @@ -861,7 +874,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) pxa3xx_nand_data_dma_irq, info); if (info->data_dma_ch < 0) { dev_err(&pdev->dev, "failed to request data dma\n"); - dma_free_coherent(&pdev->dev, info->data_buff_size, + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); return info->data_dma_ch; } @@ -871,21 +884,25 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) { - struct mtd_info *mtd = info->mtd; - struct nand_chip *chip = mtd->priv; + struct mtd_info *mtd = info->host->mtd; + int ret; /* use the common timing to make a try */ - pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); - chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); + ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); + if (ret) + return ret; + + pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0); if (info->is_ready) - return 1; - else return 0; + + return -ENODEV; } static int pxa3xx_nand_scan(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; @@ -899,12 +916,10 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG; ret = pxa3xx_nand_sensing(info); - if (!ret) { - kfree(mtd); - info->mtd = NULL; + if (ret) { dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n"); - return -EINVAL; + return ret; } chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); @@ -912,8 +927,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) if (id != 0) dev_info(&info->pdev->dev, "Detect a flash id %x\n", id); else { - kfree(mtd); - info->mtd = NULL; dev_warn(&info->pdev->dev, "Read out ID 0, potential timing set wrong!!\n"); @@ -933,14 +946,17 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) } if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { - kfree(mtd); - info->mtd = NULL; dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n"); return -EINVAL; } - pxa3xx_nand_config_flash(info, f); + ret = pxa3xx_nand_config_flash(info, f); + if (ret) { + dev_err(&info->pdev->dev, "ERROR! Configure failed\n"); + return ret; + } + pxa3xx_flash_ids[0].name = f->name; pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff; pxa3xx_flash_ids[0].pagesize = f->page_size; @@ -952,47 +968,56 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[1].name = NULL; def = pxa3xx_flash_ids; KEEP_CONFIG: + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = host->page_size; + + chip->options = NAND_NO_AUTOINCR; + chip->options |= NAND_NO_READRDY; + if (host->reg_ndcr & NDCR_DWIDTH_M) + chip->options |= NAND_BUSWIDTH_16; + if (nand_scan_ident(mtd, 1, def)) return -ENODEV; /* calculate addressing information */ - info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; + if (mtd->writesize >= 2048) + host->col_addr_cycles = 2; + else + host->col_addr_cycles = 1; + info->oob_buff = info->data_buff + mtd->writesize; if ((mtd->size >> chip->page_shift) > 65536) - info->row_addr_cycles = 3; + host->row_addr_cycles = 3; else - info->row_addr_cycles = 2; - mtd->name = mtd_names[0]; - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = info->page_size; - - chip->options = (info->reg_ndcr & NDCR_DWIDTH_M) ? NAND_BUSWIDTH_16 : 0; - chip->options |= NAND_NO_AUTOINCR; - chip->options |= NAND_NO_READRDY; + host->row_addr_cycles = 2; + mtd->name = mtd_names[0]; return nand_scan_tail(mtd); } -static -struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) +static int alloc_nand_resource(struct platform_device *pdev) { struct pxa3xx_nand_info *info; + struct pxa3xx_nand_host *host; struct nand_chip *chip; struct mtd_info *mtd; struct resource *r; int ret, irq; - mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), + info = kzalloc(sizeof(*info) + sizeof(*mtd) + sizeof(*host), GFP_KERNEL); - if (!mtd) { + if (!info) { dev_err(&pdev->dev, "failed to allocate memory\n"); - return NULL; + return -ENOMEM; } - info = (struct pxa3xx_nand_info *)(&mtd[1]); + mtd = (struct mtd_info *)(&info[1]); chip = (struct nand_chip *)(&mtd[1]); + host = (struct pxa3xx_nand_host *)chip; info->pdev = pdev; - info->mtd = mtd; - mtd->priv = info; + info->host = host; + host->mtd = mtd; + host->info_data = info; + mtd->priv = host; mtd->owner = THIS_MODULE; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; @@ -1000,7 +1025,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) chip->controller = &info->controller; chip->waitfunc = pxa3xx_nand_waitfunc; chip->select_chip = pxa3xx_nand_select_chip; - chip->dev_ready = pxa3xx_nand_dev_ready; chip->cmdfunc = pxa3xx_nand_cmdfunc; chip->read_word = pxa3xx_nand_read_word; chip->read_byte = pxa3xx_nand_read_byte; @@ -1079,13 +1103,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) platform_set_drvdata(pdev, info); - return info; + return 0; fail_free_buf: free_irq(irq, info); if (use_dma) { pxa_free_dma(info->data_dma_ch); - dma_free_coherent(&pdev->dev, info->data_buff_size, + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); } else kfree(info->data_buff); @@ -1097,17 +1121,19 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) clk_disable(info->clk); clk_put(info->clk); fail_free_mtd: - kfree(mtd); - return NULL; + kfree(info); + return ret; } static int pxa3xx_nand_remove(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; struct resource *r; int irq; + if (!info) + return 0; + platform_set_drvdata(pdev, NULL); irq = platform_get_irq(pdev, 0); @@ -1115,7 +1141,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) free_irq(irq, info); if (use_dma) { pxa_free_dma(info->data_dma_ch); - dma_free_writecombine(&pdev->dev, info->data_buff_size, + dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); } else kfree(info->data_buff); @@ -1127,10 +1153,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) clk_disable(info->clk); clk_put(info->clk); - if (mtd) { - nand_release(mtd); - kfree(mtd); - } + nand_release(info->host->mtd); + kfree(info); return 0; } @@ -1138,6 +1162,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; + int ret; pdata = pdev->dev.platform_data; if (!pdata) { @@ -1145,17 +1170,20 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) return -ENODEV; } - info = alloc_nand_resource(pdev); - if (info == NULL) - return -ENOMEM; + ret = alloc_nand_resource(pdev); + if (ret) { + dev_err(&pdev->dev, "alloc nand resource failed\n"); + return ret; + } - if (pxa3xx_nand_scan(info->mtd)) { + info = platform_get_drvdata(pdev); + if (pxa3xx_nand_scan(info->host->mtd)) { dev_err(&pdev->dev, "failed to scan nand\n"); pxa3xx_nand_remove(pdev); return -ENODEV; } - return mtd_device_parse_register(info->mtd, NULL, 0, + return mtd_device_parse_register(info->host->mtd, NULL, 0, pdata->parts, pdata->nr_parts); } @@ -1182,8 +1210,8 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) /* We don't want to handle interrupt without calling mtd routine */ disable_int(info, NDCR_INT_MASK); - nand_writel(info, NDTR0CS0, info->ndtr0cs0); - nand_writel(info, NDTR1CS0, info->ndtr1cs0); + nand_writel(info, NDTR0CS0, info->host->ndtr0cs0); + nand_writel(info, NDTR1CS0, info->host->ndtr1cs0); /* * As the spec says, the NDSR would be updated to 0x1800 when From f3c8cfc237927cc095e8bcb1e3794cfa76390bab Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Thu, 14 Jul 2011 20:44:33 -0700 Subject: [PATCH 0303/1596] mtd: pxa3xx_nand: enable multiple chip select support Current pxa3xx_nand controller has two chip select which both be workable. This patch enable this feature. Update platform driver to support this feature. Another notice should be taken that: When you want to use this feature, you should not enable the keep configuration feature, for two chip select could be attached with different nand chip. The different page size and timing requirement make the keep configuration impossible. Signed-off-by: Lei Wen --- arch/arm/mach-mmp/aspenite.c | 5 +- arch/arm/mach-pxa/cm-x300.c | 5 +- arch/arm/mach-pxa/colibri-pxa3xx.c | 5 +- arch/arm/mach-pxa/littleton.c | 5 +- arch/arm/mach-pxa/mxm8x10.c | 9 +- arch/arm/mach-pxa/raumfeld.c | 5 +- arch/arm/mach-pxa/zylonite.c | 5 +- arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | 20 ++- drivers/mtd/nand/pxa3xx_nand.c | 173 +++++++++++++------ 9 files changed, 164 insertions(+), 68 deletions(-) diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c index 06b5fa853c93..c4996f3dba3b 100644 --- a/arch/arm/mach-mmp/aspenite.c +++ b/arch/arm/mach-mmp/aspenite.c @@ -167,8 +167,9 @@ static struct mtd_partition aspenite_nand_partitions[] = { static struct pxa3xx_nand_platform_data aspenite_nand_info = { .enable_arbiter = 1, - .parts = aspenite_nand_partitions, - .nr_parts = ARRAY_SIZE(aspenite_nand_partitions), + .num_cs = 1, + .parts[0] = aspenite_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(aspenite_nand_partitions), }; static struct i2c_board_info aspenite_i2c_info[] __initdata = { diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index b6a51340270b..eac3846ce42c 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c @@ -424,8 +424,9 @@ static struct mtd_partition cm_x300_nand_partitions[] = { static struct pxa3xx_nand_platform_data cm_x300_nand_info = { .enable_arbiter = 1, .keep_config = 1, - .parts = cm_x300_nand_partitions, - .nr_parts = ARRAY_SIZE(cm_x300_nand_partitions), + .num_cs = 1, + .parts[0] = cm_x300_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(cm_x300_nand_partitions), }; static void __init cm_x300_init_nand(void) diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c index 3f9be419959d..2b8ca0de8a3d 100644 --- a/arch/arm/mach-pxa/colibri-pxa3xx.c +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c @@ -139,8 +139,9 @@ static struct mtd_partition colibri_nand_partitions[] = { static struct pxa3xx_nand_platform_data colibri_nand_info = { .enable_arbiter = 1, .keep_config = 1, - .parts = colibri_nand_partitions, - .nr_parts = ARRAY_SIZE(colibri_nand_partitions), + .num_cs = 1, + .parts[0] = colibri_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(colibri_nand_partitions), }; void __init colibri_pxa3xx_init_nand(void) diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index 8f97e15e86e5..cd9fda3c9e65 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c @@ -325,8 +325,9 @@ static struct mtd_partition littleton_nand_partitions[] = { static struct pxa3xx_nand_platform_data littleton_nand_info = { .enable_arbiter = 1, - .parts = littleton_nand_partitions, - .nr_parts = ARRAY_SIZE(littleton_nand_partitions), + .num_cs = 1, + .parts[0] = littleton_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(littleton_nand_partitions), }; static void __init littleton_init_nand(void) diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c index b5a8fd3fce04..90928d6e1a5b 100644 --- a/arch/arm/mach-pxa/mxm8x10.c +++ b/arch/arm/mach-pxa/mxm8x10.c @@ -389,10 +389,11 @@ static struct mtd_partition mxm_8x10_nand_partitions[] = { }; static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = { - .enable_arbiter = 1, - .keep_config = 1, - .parts = mxm_8x10_nand_partitions, - .nr_parts = ARRAY_SIZE(mxm_8x10_nand_partitions) + .enable_arbiter = 1, + .keep_config = 1, + .num_cs = 1, + .parts[0] = mxm_8x10_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(mxm_8x10_nand_partitions) }; static void __init mxm_8x10_nand_init(void) diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index bbcd90562ebe..6a2f353de39a 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -346,8 +346,9 @@ static struct mtd_partition raumfeld_nand_partitions[] = { static struct pxa3xx_nand_platform_data raumfeld_nand_info = { .enable_arbiter = 1, .keep_config = 1, - .parts = raumfeld_nand_partitions, - .nr_parts = ARRAY_SIZE(raumfeld_nand_partitions), + .num_cs = 1, + .parts[0] = raumfeld_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(raumfeld_nand_partitions), }; /** diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c index 15ec66b3471a..90fbf879c019 100644 --- a/arch/arm/mach-pxa/zylonite.c +++ b/arch/arm/mach-pxa/zylonite.c @@ -366,8 +366,9 @@ static struct mtd_partition zylonite_nand_partitions[] = { static struct pxa3xx_nand_platform_data zylonite_nand_info = { .enable_arbiter = 1, - .parts = zylonite_nand_partitions, - .nr_parts = ARRAY_SIZE(zylonite_nand_partitions), + .num_cs = 1, + .parts[0] = zylonite_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(zylonite_nand_partitions), }; static void __init zylonite_init_nand(void) diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h index 442301fe48b4..c42f39f20195 100644 --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h @@ -41,6 +41,19 @@ struct pxa3xx_nand_flash { struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ }; +/* + * Current pxa3xx_nand controller has two chip select which + * both be workable. + * + * Notice should be taken that: + * When you want to use this feature, you should not enable the + * keep configuration feature, for two chip select could be + * attached with different nand chip. The different page size + * and timing requirement make the keep configuration impossible. + */ + +/* The max num of chip select current support */ +#define NUM_CHIP_SELECT (2) struct pxa3xx_nand_platform_data { /* the data flash bus is shared between the Static Memory @@ -52,8 +65,11 @@ struct pxa3xx_nand_platform_data { /* allow platform code to keep OBM/bootloader defined NFC config */ int keep_config; - const struct mtd_partition *parts; - unsigned int nr_parts; + /* indicate how many chip selects will be used */ + int num_cs; + + const struct mtd_partition *parts[NUM_CHIP_SELECT]; + unsigned int nr_parts[NUM_CHIP_SELECT]; const struct pxa3xx_nand_flash * flash; size_t num_flash; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 97b689499119..9eb7f879969e 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -130,6 +130,7 @@ struct pxa3xx_nand_host { /* page size of attached chip */ unsigned int page_size; int use_ecc; + int cs; /* calculated from pxa3xx_nand_flash data */ unsigned int col_addr_cycles; @@ -165,9 +166,10 @@ struct pxa3xx_nand_info { struct pxa_dma_desc *data_desc; dma_addr_t data_desc_addr; - struct pxa3xx_nand_host *host; + struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; unsigned int state; + int cs; int use_ecc; /* use HW ECC ? */ int use_dma; /* use DMA ? */ int is_ready; @@ -226,7 +228,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) -const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; +const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL}; #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) @@ -268,7 +270,7 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { - struct pxa3xx_nand_host *host = info->host; + struct pxa3xx_nand_host *host = info->host[info->cs]; int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; info->data_size = host->page_size; @@ -295,7 +297,7 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) */ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) { - struct pxa3xx_nand_host *host = info->host; + struct pxa3xx_nand_host *host = info->host[info->cs]; uint32_t ndcr; ndcr = host->reg_ndcr; @@ -420,6 +422,15 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { struct pxa3xx_nand_info *info = devid; unsigned int status, is_completed = 0; + unsigned int ready, cmd_done; + + if (info->cs == 0) { + ready = NDSR_FLASH_RDY; + cmd_done = NDSR_CS0_CMDD; + } else { + ready = NDSR_RDY; + cmd_done = NDSR_CS1_CMDD; + } status = nand_readl(info, NDSR); @@ -441,11 +452,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) handle_data_pio(info); } } - if (status & NDSR_CS0_CMDD) { + if (status & cmd_done) { info->state = STATE_CMD_DONE; is_completed = 1; } - if (status & NDSR_FLASH_RDY) { + if (status & ready) { info->is_ready = 1; info->state = STATE_READY; } @@ -480,9 +491,11 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, { uint16_t cmd; int addr_cycle, exec_cmd; - struct pxa3xx_nand_host *host = info->host; - struct mtd_info *mtd = host->mtd; + struct pxa3xx_nand_host *host; + struct mtd_info *mtd; + host = info->host[info->cs]; + mtd = host->mtd; addr_cycle = 0; exec_cmd = 1; @@ -492,8 +505,11 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size = 0; info->use_ecc = 0; info->is_ready = 0; - info->ndcb0 = 0; info->retcode = ERR_NONE; + if (info->cs != 0) + info->ndcb0 = NDCB0_CSEL; + else + info->ndcb0 = 0; switch (command) { case NAND_CMD_READ0: @@ -637,6 +653,17 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, if (host->reg_ndcr & NDCR_DWIDTH_M) column /= 2; + /* + * There may be different NAND chip hooked to + * different chip select, so check whether + * chip select has been changed, if yes, reset the timing + */ + if (info->cs != host->cs) { + info->cs = host->cs; + nand_writel(info, NDTR0CS0, host->ndtr0cs0); + nand_writel(info, NDTR1CS0, host->ndtr1cs0); + } + info->state = STATE_PREPARED; exec_cmd = prepare_command_pool(info, command, column, page_addr); if (exec_cmd) { @@ -778,7 +805,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, { struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; - struct pxa3xx_nand_host *host = info->host; + struct pxa3xx_nand_host *host = info->host[info->cs]; uint32_t ndcr = 0x0; /* enable all interrupts */ if (f->page_size != 2048 && f->page_size != 512) { @@ -822,7 +849,11 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { - struct pxa3xx_nand_host *host = info->host; + /* + * We set 0 by hard coding here, for we don't support keep_config + * when there is more than one chip attached to the controller + */ + struct pxa3xx_nand_host *host = info->host[0]; uint32_t ndcr = nand_readl(info, NDCR); if (ndcr & NDCR_PAGE_SZ) { @@ -884,9 +915,9 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) { - struct mtd_info *mtd = info->host->mtd; + struct mtd_info *mtd; int ret; - + mtd = info->host[info->cs]->mtd; /* use the common timing to make a try */ ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); if (ret) @@ -917,7 +948,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) ret = pxa3xx_nand_sensing(info); if (ret) { - dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n"); + dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", + info->cs); return ret; } @@ -996,41 +1028,47 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) static int alloc_nand_resource(struct platform_device *pdev) { + struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; struct pxa3xx_nand_host *host; struct nand_chip *chip; struct mtd_info *mtd; struct resource *r; - int ret, irq; + int ret, irq, cs; - info = kzalloc(sizeof(*info) + sizeof(*mtd) + sizeof(*host), - GFP_KERNEL); + pdata = pdev->dev.platform_data; + info = kzalloc(sizeof(*info) + (sizeof(*mtd) + + sizeof(*host)) * pdata->num_cs, GFP_KERNEL); if (!info) { dev_err(&pdev->dev, "failed to allocate memory\n"); return -ENOMEM; } - mtd = (struct mtd_info *)(&info[1]); - chip = (struct nand_chip *)(&mtd[1]); - host = (struct pxa3xx_nand_host *)chip; info->pdev = pdev; - info->host = host; - host->mtd = mtd; - host->info_data = info; - mtd->priv = host; - mtd->owner = THIS_MODULE; - - chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; - chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; - chip->controller = &info->controller; - chip->waitfunc = pxa3xx_nand_waitfunc; - chip->select_chip = pxa3xx_nand_select_chip; - chip->cmdfunc = pxa3xx_nand_cmdfunc; - chip->read_word = pxa3xx_nand_read_word; - chip->read_byte = pxa3xx_nand_read_byte; - chip->read_buf = pxa3xx_nand_read_buf; - chip->write_buf = pxa3xx_nand_write_buf; - chip->verify_buf = pxa3xx_nand_verify_buf; + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = (struct mtd_info *)((unsigned int)&info[1] + + (sizeof(*mtd) + sizeof(*host)) * cs); + chip = (struct nand_chip *)(&mtd[1]); + host = (struct pxa3xx_nand_host *)chip; + info->host[cs] = host; + host->mtd = mtd; + host->cs = cs; + host->info_data = info; + mtd->priv = host; + mtd->owner = THIS_MODULE; + + chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; + chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; + chip->controller = &info->controller; + chip->waitfunc = pxa3xx_nand_waitfunc; + chip->select_chip = pxa3xx_nand_select_chip; + chip->cmdfunc = pxa3xx_nand_cmdfunc; + chip->read_word = pxa3xx_nand_read_word; + chip->read_byte = pxa3xx_nand_read_byte; + chip->read_buf = pxa3xx_nand_read_buf; + chip->write_buf = pxa3xx_nand_write_buf; + chip->verify_buf = pxa3xx_nand_verify_buf; + } spin_lock_init(&chip->controller->lock); init_waitqueue_head(&chip->controller->wq); @@ -1128,12 +1166,14 @@ static int alloc_nand_resource(struct platform_device *pdev) static int pxa3xx_nand_remove(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); + struct pxa3xx_nand_platform_data *pdata; struct resource *r; - int irq; + int irq, cs; if (!info) return 0; + pdata = pdev->dev.platform_data; platform_set_drvdata(pdev, NULL); irq = platform_get_irq(pdev, 0); @@ -1153,7 +1193,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) clk_disable(info->clk); clk_put(info->clk); - nand_release(info->host->mtd); + for (cs = 0; cs < pdata->num_cs; cs++) + nand_release(info->host[cs]->mtd); kfree(info); return 0; } @@ -1162,7 +1203,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; - int ret; + int ret, cs, probe_success; pdata = pdev->dev.platform_data; if (!pdata) { @@ -1177,41 +1218,69 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } info = platform_get_drvdata(pdev); - if (pxa3xx_nand_scan(info->host->mtd)) { - dev_err(&pdev->dev, "failed to scan nand\n"); + probe_success = 0; + for (cs = 0; cs < pdata->num_cs; cs++) { + info->cs = cs; + ret = pxa3xx_nand_scan(info->host[cs]->mtd); + if (ret) { + dev_warn(&pdev->dev, "failed to scan nand at cs %d\n", + cs); + continue; + } + + ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0, + pdata->parts[cs], pdata->nr_parts[cs]); + if (!ret) + probe_success = 1; + } + + if (!probe_success) { pxa3xx_nand_remove(pdev); return -ENODEV; } - return mtd_device_parse_register(info->host->mtd, NULL, 0, - pdata->parts, pdata->nr_parts); + return 0; } #ifdef CONFIG_PM static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; + struct pxa3xx_nand_platform_data *pdata; + struct mtd_info *mtd; + int cs; + pdata = pdev->dev.platform_data; if (info->state) { dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); return -EAGAIN; } - mtd->suspend(mtd); + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = info->host[cs]->mtd; + mtd->suspend(mtd); + } + return 0; } static int pxa3xx_nand_resume(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; + struct pxa3xx_nand_platform_data *pdata; + struct mtd_info *mtd; + int cs; + pdata = pdev->dev.platform_data; /* We don't want to handle interrupt without calling mtd routine */ disable_int(info, NDCR_INT_MASK); - nand_writel(info, NDTR0CS0, info->host->ndtr0cs0); - nand_writel(info, NDTR1CS0, info->host->ndtr1cs0); + /* + * Directly set the chip select to a invalid value, + * then the driver would reset the timing according + * to current chip select at the beginning of cmdfunc + */ + info->cs = 0xff; /* * As the spec says, the NDSR would be updated to 0x1800 when @@ -1220,7 +1289,11 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) * all status before resume */ nand_writel(info, NDSR, NDSR_MASK); - mtd->resume(mtd); + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = info->host[cs]->mtd; + mtd->resume(mtd); + } + return 0; } #else From b94e757c4b3aafa52f8b82efed8660427a8d2880 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 15 Jul 2011 16:38:56 +0800 Subject: [PATCH 0304/1596] mtd: dataflash: add device tree probe support It adds device tree probe support for mtd_dataflash driver. Signed-off-by: Shawn Guo Signed-off-by: Artem Bityutskiy --- .../bindings/mtd/atmel-dataflash.txt | 14 ++++++++++++++ drivers/mtd/devices/mtd_dataflash.c | 18 ++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/atmel-dataflash.txt diff --git a/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt b/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt new file mode 100644 index 000000000000..ef66ddd01da0 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt @@ -0,0 +1,14 @@ +* Atmel Data Flash + +Required properties: +- compatible : "atmel,", "atmel,", "atmel,dataflash". + +Example: + +flash@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,at45db321d", "atmel,at45", "atmel,dataflash"; + spi-max-frequency = <25000000>; + reg = <1>; +}; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 8f6b02c43b43..c86fa573c303 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -24,7 +26,6 @@ #include #include - /* * DataFlash is a kind of SPI flash. Most AT45 chips have two buffers in * each chip, which may be used for double buffered I/O; but this driver @@ -98,6 +99,16 @@ struct dataflash { struct mtd_info mtd; }; +#ifdef CONFIG_OF +static const struct of_device_id dataflash_dt_ids[] = { + { .compatible = "atmel,at45", }, + { .compatible = "atmel,dataflash", }, + { /* sentinel */ } +}; +#else +#define dataflash_dt_ids NULL +#endif + /* ......................................................................... */ /* @@ -634,6 +645,7 @@ add_dataflash_otp(struct spi_device *spi, char *name, { struct dataflash *priv; struct mtd_info *device; + struct mtd_part_parser_data ppdata; struct flash_platform_data *pdata = spi->dev.platform_data; char *otp_tag = ""; int err = 0; @@ -675,7 +687,8 @@ add_dataflash_otp(struct spi_device *spi, char *name, pagesize, otp_tag); dev_set_drvdata(&spi->dev, priv); - err = mtd_device_parse_register(device, NULL, 0, + ppdata.of_node = spi->dev.of_node; + err = mtd_device_parse_register(device, NULL, &ppdata, pdata ? pdata->parts : NULL, pdata ? pdata->nr_parts : 0); @@ -926,6 +939,7 @@ static struct spi_driver dataflash_driver = { .name = "mtd_dataflash", .bus = &spi_bus_type, .owner = THIS_MODULE, + .of_match_table = dataflash_dt_ids, }, .probe = dataflash_probe, From a0f5080ecc1c75f9c08591d9b0f48451e7ac8ddc Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:06 -0700 Subject: [PATCH 0305/1596] mtd: nand: change KERN_DEBUG to KERN_INFO Soon we will change many printk statements into pr_* statements, i.e., 'printk(KERN_INFO, ...)' becomes 'pr_info(...)'. However, this means that KERN_DEBUG messages will become pr_debug() statements and therefore will not be activated by default - they must be enabled using dynamic debug. So, for important DEBUG messages, we will simply upgrade these to INFO so that they appear by default. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index a4fcbf1cbc76..0d2eaa72288f 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -219,7 +219,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { - printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", + printk(KERN_INFO "nand_read_bbt: Reserved block at 0x%012llx\n", (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); mtd->ecc_stats.bbtblocks++; @@ -227,9 +227,9 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, } /* * Leave it for now, if it's matured we can - * move this message to MTD_DEBUG_LEVEL0. + * move this message to pr_debug. */ - printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", + printk(KERN_INFO "nand_read_bbt: Bad block at 0x%012llx\n", (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); /* Factory marked bad or worn out? */ if (tmp == 0) @@ -389,7 +389,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, mtd->writesize, td); td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", + printk(KERN_INFO "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } @@ -398,7 +398,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, mtd->writesize, td); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", + printk(KERN_INFO "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } return 1; @@ -616,7 +616,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr if (td->pages[i] == -1) printk(KERN_WARNING "Bad block table not found for chip %d\n", i); else - printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], + printk(KERN_INFO "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); } return 0; @@ -847,7 +847,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (res < 0) goto outerr; - printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " + printk(KERN_INFO "Bad block table written to 0x%012llx, version " "0x%02X\n", (unsigned long long)to, td->version[chip]); /* Mark it as used */ From 9a4d4d69018e7b719ba58fa30fcdd60e547776b8 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:07 -0700 Subject: [PATCH 0306/1596] mtd: nand: convert printk() to pr_*() Instead of directly calling printk, it's simpler to use the built-in pr_* functions. This shortens code and allows easy customization through the definition of a pr_fmt() macro (not used currently). Ideally, we could implement much of this with dev_* functions, but the MTD subsystem does not necessarily register all its master `mtd_info.dev` device, so we cannot use dev_* consistently. See: http://lists.infradead.org/pipermail/linux-mtd/2011-July/036950.html Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 44 ++++++++++++++++++------------------ drivers/mtd/nand/nand_bbt.c | 34 ++++++++++++++-------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 250e86f5592e..1d6c81aef779 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2179,7 +2179,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /* Reject writes, which are not page aligned */ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { - printk(KERN_NOTICE "%s: Attempt to write not " + pr_notice("%s: Attempt to write not " "page aligned data\n", __func__); return -EINVAL; } @@ -2570,7 +2570,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* Heck if we have a bad block, we do not erase bad blocks! */ if (nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { - printk(KERN_WARNING "%s: attempt to erase a bad block " + pr_warn("%s: attempt to erase a bad block " "at page 0x%08x\n", __func__, page); instr->state = MTD_ERASE_FAILED; goto erase_exit; @@ -2744,7 +2744,7 @@ static void nand_resume(struct mtd_info *mtd) if (chip->state == FL_PM_SUSPENDED) nand_release_device(mtd); else - printk(KERN_ERR "%s called for a chip which is not " + pr_err("%s called for a chip which is not " "in suspended state\n", __func__); } @@ -2836,13 +2836,13 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') return 0; - printk(KERN_INFO "ONFI flash detected\n"); + pr_info("ONFI flash detected\n"); chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { - printk(KERN_INFO "ONFI param page %d valid\n", i); + pr_info("ONFI param page %d valid\n", i); break; } } @@ -2866,7 +2866,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->onfi_version = 0; if (!chip->onfi_version) { - printk(KERN_INFO "%s: unsupported ONFI version: %d\n", + pr_info("%s: unsupported ONFI version: %d\n", __func__, val); return 0; } @@ -2932,7 +2932,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, id_data[i] = chip->read_byte(mtd); if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - printk(KERN_INFO "%s: second ID read did not match " + pr_info("%s: second ID read did not match " "%02x,%02x against %02x,%02x\n", __func__, *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); @@ -3077,10 +3077,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, * chip correct! */ if (busw != (chip->options & NAND_BUSWIDTH_16)) { - printk(KERN_INFO "NAND device: Manufacturer ID:" + pr_info("NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); - printk(KERN_WARNING "NAND bus width %d instead %d bit\n", + pr_warn("NAND bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); return ERR_PTR(-EINVAL); @@ -3138,7 +3138,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - printk(KERN_INFO "NAND device: Manufacturer ID:" + pr_info("NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, chip->onfi_version ? chip->onfi_params.model : type->name); @@ -3175,7 +3175,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) - printk(KERN_WARNING "No NAND device found.\n"); + pr_warn("No NAND device found.\n"); chip->select_chip(mtd, -1); return PTR_ERR(type); } @@ -3193,7 +3193,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, break; } if (i > 1) - printk(KERN_INFO "%d NAND chips detected\n", i); + pr_info("%d NAND chips detected\n", i); /* Store the number of chips and calc total size for mtd */ chip->numchips = i; @@ -3243,7 +3243,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.layout = &nand_oob_128; break; default: - printk(KERN_WARNING "No oob scheme defined for " + pr_warn("No oob scheme defined for " "oobsize %d\n", mtd->oobsize); BUG(); } @@ -3262,7 +3262,7 @@ int nand_scan_tail(struct mtd_info *mtd) /* Similar to NAND_ECC_HW, but a separate read_page handle */ if (!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) { - printk(KERN_WARNING "No ECC functions supplied; " + pr_warn("No ECC functions supplied; " "Hardware ECC not possible\n"); BUG(); } @@ -3291,7 +3291,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.read_page == nand_read_page_hwecc || !chip->ecc.write_page || chip->ecc.write_page == nand_write_page_hwecc)) { - printk(KERN_WARNING "No ECC functions supplied; " + pr_warn("No ECC functions supplied; " "Hardware ECC not possible\n"); BUG(); } @@ -3311,7 +3311,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (mtd->writesize >= chip->ecc.size) break; - printk(KERN_WARNING "%d byte HW ECC not possible on " + pr_warn("%d byte HW ECC not possible on " "%d byte page size, fallback to SW ECC\n", chip->ecc.size, mtd->writesize); chip->ecc.mode = NAND_ECC_SOFT; @@ -3333,7 +3333,7 @@ int nand_scan_tail(struct mtd_info *mtd) case NAND_ECC_SOFT_BCH: if (!mtd_nand_has_bch()) { - printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); + pr_warn("CONFIG_MTD_ECC_BCH not enabled\n"); BUG(); } chip->ecc.calculate = nand_bch_calculate_ecc; @@ -3360,13 +3360,13 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.bytes, &chip->ecc.layout); if (!chip->ecc.priv) { - printk(KERN_WARNING "BCH ECC initialization failed!\n"); + pr_warn("BCH ECC initialization failed!\n"); BUG(); } break; case NAND_ECC_NONE: - printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " + pr_warn("NAND_ECC_NONE selected by board driver. " "This is not recommended !!\n"); chip->ecc.read_page = nand_read_page_raw; chip->ecc.write_page = nand_write_page_raw; @@ -3379,7 +3379,7 @@ int nand_scan_tail(struct mtd_info *mtd) break; default: - printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", + pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); BUG(); } @@ -3401,7 +3401,7 @@ int nand_scan_tail(struct mtd_info *mtd) */ chip->ecc.steps = mtd->writesize / chip->ecc.size; if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { - printk(KERN_WARNING "Invalid ECC parameters\n"); + pr_warn("Invalid ECC parameters\n"); BUG(); } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; @@ -3492,7 +3492,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips) /* Many callers got this wrong, so check for it for a while... */ if (!mtd->owner && caller_is_module()) { - printk(KERN_CRIT "%s called with NULL mtd->owner!\n", + pr_crit("%s called with NULL mtd->owner!\n", __func__); BUG(); } diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 0d2eaa72288f..76f496d2bfed 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -205,10 +205,10 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, res = mtd->read(mtd, from, len, &retlen, buf); if (res < 0) { if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); + pr_info("nand_bbt: Error reading bad block table\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); + pr_warn("nand_bbt: ECC error while reading bad block table\n"); } /* Analyse data */ @@ -219,7 +219,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { - printk(KERN_INFO "nand_read_bbt: Reserved block at 0x%012llx\n", + pr_info("nand_read_bbt: Reserved block at 0x%012llx\n", (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); mtd->ecc_stats.bbtblocks++; @@ -229,7 +229,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, * Leave it for now, if it's matured we can * move this message to pr_debug. */ - printk(KERN_INFO "nand_read_bbt: Bad block at 0x%012llx\n", + pr_info("nand_read_bbt: Bad block at 0x%012llx\n", (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); /* Factory marked bad or worn out? */ if (tmp == 0) @@ -389,7 +389,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, mtd->writesize, td); td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; - printk(KERN_INFO "Bad block table at page %d, version 0x%02X\n", + pr_info("Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } @@ -398,7 +398,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, mtd->writesize, td); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; - printk(KERN_INFO "Bad block table at page %d, version 0x%02X\n", + pr_info("Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } return 1; @@ -473,7 +473,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, loff_t from; size_t readlen; - printk(KERN_INFO "Scanning device for bad blocks\n"); + pr_info("Scanning device for bad blocks\n"); if (bd->options & NAND_BBT_SCANALLPAGES) len = 1 << (this->bbt_erase_shift - this->page_shift); @@ -502,7 +502,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, from = 0; } else { if (chip >= this->numchips) { - printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", + pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", chip + 1, this->numchips); return -EINVAL; } @@ -531,7 +531,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, if (ret) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n", + pr_warn("Bad eraseblock %d at 0x%012llx\n", i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; } @@ -614,9 +614,9 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { if (td->pages[i] == -1) - printk(KERN_WARNING "Bad block table not found for chip %d\n", i); + pr_warn("Bad block table not found for chip %d\n", i); else - printk(KERN_INFO "Bad block table found at page %d, version 0x%02X\n", td->pages[i], + pr_info("Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); } return 0; @@ -730,7 +730,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (!md || md->pages[chip] != page) goto write; } - printk(KERN_ERR "No space left to write bad block table\n"); + pr_err("No space left to write bad block table\n"); return -ENOSPC; write: @@ -765,12 +765,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, res = mtd->read(mtd, to, len, &retlen, buf); if (res < 0) { if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error " + pr_info("nand_bbt: Error " "reading block for writing " "the bad block table\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error " + pr_warn("nand_bbt: ECC error " "while reading block for writing " "bad block table\n"); } @@ -847,7 +847,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (res < 0) goto outerr; - printk(KERN_INFO "Bad block table written to 0x%012llx, version " + pr_info("Bad block table written to 0x%012llx, version " "0x%02X\n", (unsigned long long)to, td->version[chip]); /* Mark it as used */ @@ -1137,7 +1137,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) */ if (!td) { if ((res = nand_memory_bbt(mtd, bd))) { - printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); + pr_err("nand_bbt: Can't scan flash and build the RAM-based BBT\n"); kfree(this->bbt); this->bbt = NULL; } @@ -1305,7 +1305,7 @@ static int nand_create_default_bbt_descr(struct nand_chip *this) { struct nand_bbt_descr *bd; if (this->badblock_pattern) { - printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); + pr_warn("BBT descr already allocated; not replacing.\n"); return -EINVAL; } bd = kzalloc(sizeof(*bd), GFP_KERNEL); From d037021953922ebdbc34b98b8c4648017b1c6e89 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:08 -0700 Subject: [PATCH 0307/1596] mtd: nand: style fixups in pr_* messages This is a cleanup of some punctuation, indentation, and capitalization on the lines affected affected by the last patch. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 49 +++++++++++++++++------------------- drivers/mtd/nand/nand_bbt.c | 41 ++++++++++++++---------------- 2 files changed, 42 insertions(+), 48 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1d6c81aef779..6a5271256245 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2179,8 +2179,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /* Reject writes, which are not page aligned */ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { - pr_notice("%s: Attempt to write not " - "page aligned data\n", __func__); + pr_notice("%s: attempt to write non page aligned data\n", + __func__); return -EINVAL; } @@ -2570,8 +2570,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* Heck if we have a bad block, we do not erase bad blocks! */ if (nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { - pr_warn("%s: attempt to erase a bad block " - "at page 0x%08x\n", __func__, page); + pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", + __func__, page); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2744,8 +2744,8 @@ static void nand_resume(struct mtd_info *mtd) if (chip->state == FL_PM_SUSPENDED) nand_release_device(mtd); else - pr_err("%s called for a chip which is not " - "in suspended state\n", __func__); + pr_err("%s called for a chip which is not in suspended state\n", + __func__); } /* Set default functions */ @@ -2866,8 +2866,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->onfi_version = 0; if (!chip->onfi_version) { - pr_info("%s: unsupported ONFI version: %d\n", - __func__, val); + pr_info("%s: unsupported ONFI version: %d\n", __func__, val); return 0; } @@ -2933,8 +2932,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (id_data[0] != *maf_id || id_data[1] != *dev_id) { pr_info("%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, *dev_id, id_data[0], id_data[1]); + "%02x,%02x against %02x,%02x\n", __func__, + *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); } @@ -3078,11 +3077,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, */ if (busw != (chip->options & NAND_BUSWIDTH_16)) { pr_info("NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, + *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); pr_warn("NAND bus width %d instead %d bit\n", - (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); + (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, + busw ? 16 : 8); return ERR_PTR(-EINVAL); } @@ -3175,7 +3174,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) - pr_warn("No NAND device found.\n"); + pr_warn("No NAND device found\n"); chip->select_chip(mtd, -1); return PTR_ERR(type); } @@ -3243,8 +3242,8 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.layout = &nand_oob_128; break; default: - pr_warn("No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + pr_warn("No oob scheme defined for oobsize %d\n", + mtd->oobsize); BUG(); } } @@ -3263,7 +3262,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) { pr_warn("No ECC functions supplied; " - "Hardware ECC not possible\n"); + "hardware ECC not possible\n"); BUG(); } if (!chip->ecc.read_page) @@ -3292,7 +3291,7 @@ int nand_scan_tail(struct mtd_info *mtd) !chip->ecc.write_page || chip->ecc.write_page == nand_write_page_hwecc)) { pr_warn("No ECC functions supplied; " - "Hardware ECC not possible\n"); + "hardware ECC not possible\n"); BUG(); } /* Use standard syndrome read/write page function? */ @@ -3312,8 +3311,8 @@ int nand_scan_tail(struct mtd_info *mtd) if (mtd->writesize >= chip->ecc.size) break; pr_warn("%d byte HW ECC not possible on " - "%d byte page size, fallback to SW ECC\n", - chip->ecc.size, mtd->writesize); + "%d byte page size, fallback to SW ECC\n", + chip->ecc.size, mtd->writesize); chip->ecc.mode = NAND_ECC_SOFT; case NAND_ECC_SOFT: @@ -3367,7 +3366,7 @@ int nand_scan_tail(struct mtd_info *mtd) case NAND_ECC_NONE: pr_warn("NAND_ECC_NONE selected by board driver. " - "This is not recommended !!\n"); + "This is not recommended!\n"); chip->ecc.read_page = nand_read_page_raw; chip->ecc.write_page = nand_write_page_raw; chip->ecc.read_oob = nand_read_oob_std; @@ -3379,8 +3378,7 @@ int nand_scan_tail(struct mtd_info *mtd) break; default: - pr_warn("Invalid NAND_ECC_MODE %d\n", - chip->ecc.mode); + pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); BUG(); } @@ -3492,8 +3490,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips) /* Many callers got this wrong, so check for it for a while... */ if (!mtd->owner && caller_is_module()) { - pr_crit("%s called with NULL mtd->owner!\n", - __func__); + pr_crit("%s called with NULL mtd->owner!\n", __func__); BUG(); } diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 76f496d2bfed..dba332327d4f 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -205,7 +205,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, res = mtd->read(mtd, from, len, &retlen, buf); if (res < 0) { if (retlen != len) { - pr_info("nand_bbt: Error reading bad block table\n"); + pr_info("nand_bbt: error reading bad block table\n"); return res; } pr_warn("nand_bbt: ECC error while reading bad block table\n"); @@ -219,8 +219,8 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { - pr_info("nand_read_bbt: Reserved block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + pr_info("nand_read_bbt: reserved block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); mtd->ecc_stats.bbtblocks++; continue; @@ -229,8 +229,8 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, * Leave it for now, if it's matured we can * move this message to pr_debug. */ - pr_info("nand_read_bbt: Bad block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + pr_info("nand_read_bbt: bad block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); /* Factory marked bad or worn out? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); @@ -390,7 +390,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, mtd->writesize, td); td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; pr_info("Bad block table at page %d, version 0x%02X\n", - td->pages[0], td->version[0]); + td->pages[0], td->version[0]); } /* Read the mirror version, if available */ @@ -399,7 +399,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, mtd->writesize, td); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; pr_info("Bad block table at page %d, version 0x%02X\n", - md->pages[0], md->version[0]); + md->pages[0], md->version[0]); } return 1; } @@ -532,7 +532,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, if (ret) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); pr_warn("Bad eraseblock %d at 0x%012llx\n", - i >> 1, (unsigned long long)from); + i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; } @@ -616,8 +616,8 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr if (td->pages[i] == -1) pr_warn("Bad block table not found for chip %d\n", i); else - pr_info("Bad block table found at page %d, version 0x%02X\n", td->pages[i], - td->version[i]); + pr_info("Bad block table found at page %d, version " + "0x%02X\n", td->pages[i], td->version[i]); } return 0; } @@ -765,14 +765,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, res = mtd->read(mtd, to, len, &retlen, buf); if (res < 0) { if (retlen != len) { - pr_info("nand_bbt: Error " - "reading block for writing " - "the bad block table\n"); + pr_info("nand_bbt: error reading block " + "for writing the bad block table\n"); return res; } - pr_warn("nand_bbt: ECC error " - "while reading block for writing " - "bad block table\n"); + pr_warn("nand_bbt: ECC error while reading " + "block for writing bad block table\n"); } /* Read oob data */ ops.ooblen = (len >> this->page_shift) * mtd->oobsize; @@ -847,8 +845,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (res < 0) goto outerr; - pr_info("Bad block table written to 0x%012llx, version " - "0x%02X\n", (unsigned long long)to, td->version[chip]); + pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", + (unsigned long long)to, td->version[chip]); /* Mark it as used */ td->pages[chip] = page; @@ -856,8 +854,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, return 0; outerr: - printk(KERN_WARNING - "nand_bbt: Error while writing bad block table %d\n", res); + pr_warn("nand_bbt: error while writing bad block table %d\n", res); return res; } @@ -1137,7 +1134,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) */ if (!td) { if ((res = nand_memory_bbt(mtd, bd))) { - pr_err("nand_bbt: Can't scan flash and build the RAM-based BBT\n"); + pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); kfree(this->bbt); this->bbt = NULL; } @@ -1305,7 +1302,7 @@ static int nand_create_default_bbt_descr(struct nand_chip *this) { struct nand_bbt_descr *bd; if (this->badblock_pattern) { - pr_warn("BBT descr already allocated; not replacing.\n"); + pr_warn("BBT descr already allocated; not replacing\n"); return -EINVAL; } bd = kzalloc(sizeof(*bd), GFP_KERNEL); From 289c05222172b51401dbbb017115655f241d94ab Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:09 -0700 Subject: [PATCH 0308/1596] mtd: replace DEBUG() with pr_debug() Start moving away from the MTD_DEBUG_LEVEL messages. The dynamic debugging feature is a generic kernel feature that provides more flexibility. (See Documentation/dynamic-debug-howto.txt) Also fix some punctuation, indentation, and capitalization that went along with the affected lines. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/chips/cfi_cmdset_0002.c | 27 +++++------ drivers/mtd/chips/fwh_lock.h | 3 +- drivers/mtd/chips/jedec_probe.c | 32 +++++-------- drivers/mtd/devices/doc2000.c | 11 ++--- drivers/mtd/devices/doc2001.c | 5 +- drivers/mtd/devices/doc2001plus.c | 5 +- drivers/mtd/devices/m25p80.c | 20 ++++---- drivers/mtd/devices/mtd_dataflash.c | 43 ++++++++--------- drivers/mtd/devices/sst25l.c | 3 +- drivers/mtd/ftl.c | 38 +++++++-------- drivers/mtd/inftlcore.c | 38 +++++++-------- drivers/mtd/inftlmount.c | 12 ++--- drivers/mtd/mtdblock.c | 14 +++--- drivers/mtd/mtdchar.c | 10 ++-- drivers/mtd/mtdcore.c | 2 +- drivers/mtd/mtdsuper.c | 20 ++++---- drivers/mtd/nand/mxc_nand.c | 14 +++--- drivers/mtd/nand/nand_base.c | 74 ++++++++++++++--------------- drivers/mtd/nand/nand_bbt.c | 5 +- drivers/mtd/nand/nand_bch.c | 2 +- drivers/mtd/nand/omap2.c | 8 ++-- drivers/mtd/nand/rtc_from4.c | 2 +- drivers/mtd/nftlcore.c | 23 +++++---- drivers/mtd/onenand/onenand_base.c | 18 +++---- drivers/mtd/onenand/onenand_bbt.c | 2 +- drivers/mtd/ssfdc.c | 34 +++++-------- 26 files changed, 216 insertions(+), 249 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 23175edd5634..2302cc00b4a9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -145,8 +145,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) if (((major << 8) | minor) < 0x3131) { /* CFI version 1.0 => don't trust bootloc */ - DEBUG(MTD_DEBUG_LEVEL1, - "%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n", + pr_debug("%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n", map->name, cfi->mfr, cfi->id); /* AFAICS all 29LV400 with a bottom boot block have a device ID @@ -166,8 +165,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) * the 8-bit device ID. */ (cfi->mfr == CFI_MFR_MACRONIX)) { - DEBUG(MTD_DEBUG_LEVEL1, - "%s: Macronix MX29LV400C with bottom boot block" + pr_debug("%s: Macronix MX29LV400C with bottom boot block" " detected\n", map->name); extp->TopBottom = 2; /* bottom boot */ } else @@ -178,8 +176,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) extp->TopBottom = 2; /* bottom boot */ } - DEBUG(MTD_DEBUG_LEVEL1, - "%s: AMD CFI PRI V%c.%c has no boot block field;" + pr_debug("%s: AMD CFI PRI V%c.%c has no boot block field;" " deduced %s from Device ID\n", map->name, major, minor, extp->TopBottom == 2 ? "bottom" : "top"); } @@ -191,7 +188,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; if (cfi->cfiq->BufWriteTimeoutTyp) { - DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" ); + pr_debug("Using buffer write method\n" ); mtd->write = cfi_amdstd_write_buffers; } } @@ -443,7 +440,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) mtd->writesize = 1; mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", + pr_debug("MTD %s(): write buffer size %d\n", __func__, mtd->writebufsize); mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; @@ -1163,7 +1160,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", + pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, datum.x[0] ); /* @@ -1174,7 +1171,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, */ oldd = map_read(map, adr); if (map_word_equal(map, oldd, datum)) { - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n", + pr_debug("MTD %s(): NOP\n", __func__); goto op_done; } @@ -1400,7 +1397,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, datum = map_word_load(map, buf); - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", + pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, datum.x[0] ); XIP_INVAL_CACHED_RANGE(map, adr, len); @@ -1587,7 +1584,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + pr_debug("MTD %s(): ERASE 0x%.8lx\n", __func__, chip->start ); XIP_INVAL_CACHED_RANGE(map, adr, map->size); @@ -1675,7 +1672,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + pr_debug("MTD %s(): ERASE 0x%.8lx\n", __func__, adr ); XIP_INVAL_CACHED_RANGE(map, adr, len); @@ -1801,7 +1798,7 @@ static int do_atmel_lock(struct map_info *map, struct flchip *chip, goto out_unlock; chip->state = FL_LOCKING; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", + pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, @@ -1837,7 +1834,7 @@ static int do_atmel_unlock(struct map_info *map, struct flchip *chip, goto out_unlock; chip->state = FL_UNLOCKING; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", + pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index 5e3cc80128aa..89c6595454a5 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -34,8 +34,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, /* Refuse the operation if the we cannot look behind the chip */ if (chip->start < 0x400000) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): chip->start: %lx wanted >= 0x400000\n", + pr_debug( "MTD %s(): chip->start: %lx wanted >= 0x400000\n", __func__, chip->start ); return -EIO; } diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index d40c410a3241..c443f527a53a 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1917,8 +1917,7 @@ static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi) * as they will ignore the writes and don't care what address * the F0 is written to */ if (cfi->addr_unlock1) { - DEBUG( MTD_DEBUG_LEVEL3, - "reset unlock called %x %x \n", + pr_debug( "reset unlock called %x %x \n", cfi->addr_unlock1,cfi->addr_unlock2); cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); @@ -1941,7 +1940,7 @@ static int cfi_jedec_setup(struct map_info *map, struct cfi_private *cfi, int in uint8_t uaddr; if (!(jedec_table[index].devtypes & cfi->device_type)) { - DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n", + pr_debug("Rejecting potential %s with incompatible %d-bit device type\n", jedec_table[index].name, 4 * (1<device_type)); return 0; } @@ -2021,7 +2020,7 @@ static inline int jedec_match( uint32_t base, * there aren't. */ if (finfo->dev_id > 0xff) { - DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n", + pr_debug("%s(): ID is not 8bit\n", __func__); goto match_done; } @@ -2045,12 +2044,10 @@ static inline int jedec_match( uint32_t base, } /* the part size must fit in the memory window */ - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", + pr_debug("MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", __func__, base, 1 << finfo->dev_size, base + (1 << finfo->dev_size) ); if ( base + cfi_interleave(cfi) * ( 1 << finfo->dev_size ) > map->size ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", + pr_debug("MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", __func__, finfo->mfr_id, finfo->dev_id, 1 << finfo->dev_size ); goto match_done; @@ -2061,13 +2058,12 @@ static inline int jedec_match( uint32_t base, uaddr = finfo->uaddr; - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", + pr_debug("MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr && ( unlock_addrs[uaddr].addr1 / cfi->device_type != cfi->addr_unlock1 || unlock_addrs[uaddr].addr2 / cfi->device_type != cfi->addr_unlock2 ) ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): 0x%.4x 0x%.4x did not match\n", + pr_debug("MTD %s(): 0x%.4x 0x%.4x did not match\n", __func__, unlock_addrs[uaddr].addr1, unlock_addrs[uaddr].addr2); @@ -2083,15 +2079,13 @@ static inline int jedec_match( uint32_t base, * FIXME - write a driver that takes all of the chip info as * module parameters, doesn't probe but forces a load. */ - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): check ID's disappear when not in ID mode\n", + pr_debug("MTD %s(): check ID's disappear when not in ID mode\n", __func__ ); jedec_reset( base, map, cfi ); mfr = jedec_read_mfr( map, base, cfi ); id = jedec_read_id( map, base, cfi ); if ( mfr == cfi->mfr && id == cfi->id ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" + pr_debug("MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" "You might need to manually specify JEDEC parameters.\n", __func__, cfi->mfr, cfi->id ); goto match_done; @@ -2104,7 +2098,7 @@ static inline int jedec_match( uint32_t base, * Put the device back in ID mode - only need to do this if we * were truly frobbing a real device. */ - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); + pr_debug("MTD %s(): return to ID mode\n", __func__ ); if (cfi->addr_unlock1) { cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); @@ -2167,13 +2161,11 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, cfi->mfr = jedec_read_mfr(map, base, cfi); cfi->id = jedec_read_id(map, base, cfi); - DEBUG(MTD_DEBUG_LEVEL3, - "Search for id:(%02x %02x) interleave(%d) type(%d)\n", + pr_debug("Search for id:(%02x %02x) interleave(%d) type(%d)\n", cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); for (i = 0; i < ARRAY_SIZE(jedec_table); i++) { if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", + pr_debug("MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", __func__, cfi->mfr, cfi->id, cfi->addr_unlock1, cfi->addr_unlock2 ); if (!cfi_jedec_setup(map, cfi, i)) diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index ed15447c392e..8c9703309496 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -82,8 +82,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc) void __iomem *docptr = doc->virtadr; unsigned long timeo = jiffies + (HZ * 10); - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { @@ -92,7 +91,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc) DoC_Delay(doc, 2); if (time_after(jiffies, timeo)) { - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return -EIO; } udelay(1); @@ -323,8 +322,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) /* Reset the chip */ if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) { - DEBUG(MTD_DEBUG_LEVEL2, - "DoC_Command (reset) for %d,%d returned true\n", + pr_debug("DoC_Command (reset) for %d,%d returned true\n", floor, chip); return 0; } @@ -332,8 +330,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) /* Read the NAND chip ID: 1. Send ReadID command */ if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) { - DEBUG(MTD_DEBUG_LEVEL2, - "DoC_Command (ReadID) for %d,%d returned true\n", + pr_debug("DoC_Command (ReadID) for %d,%d returned true\n", floor, chip); return 0; } diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index c6ea8604a3c3..3d2b459cea92 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -55,15 +55,14 @@ static int _DoC_WaitReady(void __iomem * docptr) { unsigned short c = 0xffff; - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c) ; if (c == 0) - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return (c == 0); } diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index fe82fbfa155e..d28c9d99979f 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -61,15 +61,14 @@ static int _DoC_WaitReady(void __iomem * docptr) { unsigned int c = 0xffff; - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c) ; if (c == 0) - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return (c == 0); } diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 66a3555f07d9..6417bd6b36ff 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -208,7 +208,7 @@ static int wait_till_ready(struct m25p *flash) */ static int erase_chip(struct m25p *flash) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n", + pr_debug("%s: %s %lldKiB\n", dev_name(&flash->spi->dev), __func__, (long long)(flash->mtd.size >> 10)); @@ -249,7 +249,7 @@ static int m25p_cmdsz(struct m25p *flash) */ static int erase_sector(struct m25p *flash, u32 offset) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", + pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev), __func__, flash->mtd.erasesize / 1024, offset); @@ -285,7 +285,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) u32 addr,len; uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n", + pr_debug("%s: %s %s 0x%llx, len %lld\n", dev_name(&flash->spi->dev), __func__, "at", (long long)instr->addr, (long long)instr->len); @@ -347,7 +347,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer t[2]; struct spi_message m; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", + pr_debug("%s: %s %s 0x%08x, len %zd\n", dev_name(&flash->spi->dev), __func__, "from", (u32)from, len); @@ -416,7 +416,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_transfer t[2]; struct spi_message m; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", + pr_debug("%s: %s %s 0x%08x, len %zd\n", dev_name(&flash->spi->dev), __func__, "to", (u32)to, len); @@ -509,7 +509,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t actual; int cmd_sz, ret; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", + pr_debug("%s: %s %s 0x%08x, len %zd\n", dev_name(&flash->spi->dev), __func__, "to", (u32)to, len); @@ -787,7 +787,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) */ tmp = spi_write_then_read(spi, &code, 1, id, 5); if (tmp < 0) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", + pr_debug("%s: error %d reading JEDEC ID\n", dev_name(&spi->dev), tmp); return ERR_PTR(tmp); } @@ -944,8 +944,7 @@ static int __devinit m25p_probe(struct spi_device *spi) dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, (long long)flash->mtd.size >> 10); - DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%llx (%lldMiB) " + pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), @@ -954,8 +953,7 @@ static int __devinit m25p_probe(struct spi_device *spi) if (flash->mtd.numeraseregions) for (i = 0; i < flash->mtd.numeraseregions; i++) - DEBUG(MTD_DEBUG_LEVEL2, - "mtd.eraseregions[%d] = { .offset = 0x%llx, " + pr_debug("mtd.eraseregions[%d] = { .offset = 0x%llx, " ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", i, (long long)flash->mtd.eraseregions[i].offset, diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index c86fa573c303..f409aef58ed2 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -133,7 +133,7 @@ static int dataflash_waitready(struct spi_device *spi) for (;;) { status = dataflash_status(spi); if (status < 0) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: status %d?\n", + pr_debug("%s: status %d?\n", dev_name(&spi->dev), status); status = 0; } @@ -160,7 +160,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) uint8_t *command; uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%llx len 0x%llx\n", + pr_debug("%s: erase addr=0x%llx len 0x%llx\n", dev_name(&spi->dev), (long long)instr->addr, (long long)instr->len); @@ -198,7 +198,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) command[2] = (uint8_t)(pageaddr >> 8); command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n", + pr_debug("ERASE %s: (%x) %x %x %x [%i]\n", do_block ? "block" : "page", command[0], command[1], command[2], command[3], pageaddr); @@ -249,7 +249,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, uint8_t *command; int status; - DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n", + pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len)); *retlen = 0; @@ -266,7 +266,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, command = priv->command; - DEBUG(MTD_DEBUG_LEVEL3, "READ: (%x) %x %x %x\n", + pr_debug("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); spi_message_init(&msg); @@ -298,7 +298,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, *retlen = msg.actual_length - 8; status = 0; } else - DEBUG(MTD_DEBUG_LEVEL1, "%s: read %x..%x --> %d\n", + pr_debug("%s: read %x..%x --> %d\n", dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len), status); @@ -325,7 +325,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, int status = -EINVAL; uint8_t *command; - DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n", + pr_debug("%s: write 0x%x..0x%x\n", dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len)); *retlen = 0; @@ -351,7 +351,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, mutex_lock(&priv->lock); while (remaining > 0) { - DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n", + pr_debug("write @ %i:%i len=%i\n", pageaddr, offset, writelen); /* REVISIT: @@ -379,12 +379,12 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n", + pr_debug("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); status = spi_sync(spi, &msg); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n", + pr_debug("%s: xfer %u -> %d \n", dev_name(&spi->dev), addr, status); (void) dataflash_waitready(priv->spi); @@ -397,7 +397,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = (addr & 0x000000FF); - DEBUG(MTD_DEBUG_LEVEL3, "PROGRAM: (%x) %x %x %x\n", + pr_debug("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); x[1].tx_buf = writebuf; @@ -406,7 +406,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, status = spi_sync(spi, &msg); spi_transfer_del(x + 1); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n", + pr_debug("%s: pgm %u/%u -> %d \n", dev_name(&spi->dev), addr, writelen, status); (void) dataflash_waitready(priv->spi); @@ -421,12 +421,12 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n", + pr_debug("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); status = spi_sync(spi, &msg); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n", + pr_debug("%s: compare %u -> %d \n", dev_name(&spi->dev), addr, status); status = dataflash_waitready(priv->spi); @@ -780,7 +780,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) */ tmp = spi_write_then_read(spi, &code, 1, id, 3); if (tmp < 0) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", + pr_debug("%s: error %d reading JEDEC ID\n", dev_name(&spi->dev), tmp); return ERR_PTR(tmp); } @@ -797,7 +797,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) tmp < ARRAY_SIZE(dataflash_data); tmp++, info++) { if (info->jedec_id == jedec) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: OTP, sector protect%s\n", + pr_debug("%s: OTP, sector protect%s\n", dev_name(&spi->dev), (info->flags & SUP_POW2PS) ? ", binary pagesize" : "" @@ -805,8 +805,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) if (info->flags & SUP_POW2PS) { status = dataflash_status(spi); if (status < 0) { - DEBUG(MTD_DEBUG_LEVEL1, - "%s: status error %d\n", + pr_debug("%s: status error %d\n", dev_name(&spi->dev), status); return ERR_PTR(status); } @@ -871,7 +870,7 @@ static int __devinit dataflash_probe(struct spi_device *spi) */ status = dataflash_status(spi); if (status <= 0 || status == 0xff) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n", + pr_debug("%s: status error %d\n", dev_name(&spi->dev), status); if (status == 0 || status == 0xff) status = -ENODEV; @@ -907,13 +906,13 @@ static int __devinit dataflash_probe(struct spi_device *spi) break; /* obsolete AT45DB1282 not (yet?) supported */ default: - DEBUG(MTD_DEBUG_LEVEL1, "%s: unsupported device (%x)\n", + pr_debug("%s: unsupported device (%x)\n", dev_name(&spi->dev), status & 0x3c); status = -ENODEV; } if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: add_dataflash --> %d\n", + pr_debug("%s: add_dataflash --> %d\n", dev_name(&spi->dev), status); return status; @@ -924,7 +923,7 @@ static int __devexit dataflash_remove(struct spi_device *spi) struct dataflash *flash = dev_get_drvdata(&spi->dev); int status; - DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", dev_name(&spi->dev)); + pr_debug("%s: remove\n", dev_name(&spi->dev)); status = mtd_device_unregister(&flash->mtd); if (status == 0) { diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 44a8b408ed7b..d38ef3bffe8d 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -410,8 +410,7 @@ static int __devinit sst25l_probe(struct spi_device *spi) dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name, (long long)flash->mtd.size >> 10); - DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%llx (%lldMiB) " + pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 037b399df3f1..95d77680ad15 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -339,7 +339,7 @@ static int erase_xfer(partition_t *part, struct erase_info *erase; xfer = &part->XferInfo[xfernum]; - DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); + pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); xfer->state = XFER_ERASING; /* Is there a free erase slot? Always in MTD. */ @@ -415,7 +415,7 @@ static int prepare_xfer(partition_t *part, int i) xfer = &part->XferInfo[i]; xfer->state = XFER_FAILED; - DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); + pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); /* Write the transfer unit header */ header = part->header; @@ -476,7 +476,7 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit, eun = &part->EUNInfo[srcunit]; xfer = &part->XferInfo[xferunit]; - DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", + pr_debug("ftl_cs: copying block 0x%x to 0x%x\n", eun->Offset, xfer->Offset); @@ -609,8 +609,8 @@ static int reclaim_block(partition_t *part) uint32_t best; int queued, ret; - DEBUG(0, "ftl_cs: reclaiming space...\n"); - DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits); + pr_debug("ftl_cs: reclaiming space...\n"); + pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits); /* Pick the least erased transfer unit */ best = 0xffffffff; xfer = 0xffff; do { @@ -618,22 +618,22 @@ static int reclaim_block(partition_t *part) for (i = 0; i < part->header.NumTransferUnits; i++) { int n=0; if (part->XferInfo[i].state == XFER_UNKNOWN) { - DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i); + pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i); n=1; erase_xfer(part, i); } if (part->XferInfo[i].state == XFER_ERASING) { - DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i); + pr_debug("XferInfo[%d].state == XFER_ERASING\n",i); n=1; queued = 1; } else if (part->XferInfo[i].state == XFER_ERASED) { - DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i); + pr_debug("XferInfo[%d].state == XFER_ERASED\n",i); n=1; prepare_xfer(part, i); } if (part->XferInfo[i].state == XFER_PREPARED) { - DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i); + pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i); n=1; if (part->XferInfo[i].EraseCount <= best) { best = part->XferInfo[i].EraseCount; @@ -641,12 +641,12 @@ static int reclaim_block(partition_t *part) } } if (!n) - DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); + pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); } if (xfer == 0xffff) { if (queued) { - DEBUG(1, "ftl_cs: waiting for transfer " + pr_debug("ftl_cs: waiting for transfer " "unit to be prepared...\n"); if (part->mbd.mtd->sync) part->mbd.mtd->sync(part->mbd.mtd); @@ -656,7 +656,7 @@ static int reclaim_block(partition_t *part) printk(KERN_NOTICE "ftl_cs: reclaim failed: no " "suitable transfer units!\n"); else - DEBUG(1, "ftl_cs: reclaim failed: no " + pr_debug("ftl_cs: reclaim failed: no " "suitable transfer units!\n"); return -EIO; @@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part) eun = 0; if ((jiffies % shuffle_freq) == 0) { - DEBUG(1, "ftl_cs: recycling freshest block...\n"); + pr_debug("ftl_cs: recycling freshest block...\n"); best = 0xffffffff; for (i = 0; i < part->DataUnits; i++) if (part->EUNInfo[i].EraseCount <= best) { @@ -686,7 +686,7 @@ static int reclaim_block(partition_t *part) printk(KERN_NOTICE "ftl_cs: reclaim failed: " "no free blocks!\n"); else - DEBUG(1,"ftl_cs: reclaim failed: " + pr_debug("ftl_cs: reclaim failed: " "no free blocks!\n"); return -EIO; @@ -771,7 +771,7 @@ static uint32_t find_free(partition_t *part) printk(KERN_NOTICE "ftl_cs: bad free list!\n"); return 0; } - DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); + pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun); return blk; } /* find_free */ @@ -791,7 +791,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, int ret; size_t offset, retlen; - DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", + pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", part, sector, nblocks); if (!(part->state & FTL_FORMATTED)) { printk(KERN_NOTICE "ftl_cs: bad partition\n"); @@ -840,7 +840,7 @@ static int set_bam_entry(partition_t *part, uint32_t log_addr, int ret; size_t retlen, offset; - DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", + pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", part, log_addr, virt_addr); bsize = 1 << part->header.EraseUnitSize; eun = log_addr / bsize; @@ -905,7 +905,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, int ret; size_t retlen, offset; - DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n", + pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n", part, sector, nblocks); if (!(part->state & FTL_FORMATTED)) { printk(KERN_NOTICE "ftl_cs: bad partition\n"); @@ -1011,7 +1011,7 @@ static int ftl_discardsect(struct mtd_blktrans_dev *dev, partition_t *part = (void *)dev; uint32_t bsize = 1 << part->header.EraseUnitSize; - DEBUG(1, "FTL erase sector %ld for %d sectors\n", + pr_debug("FTL erase sector %ld for %d sectors\n", sector, nr_sects); while (nr_sects) { diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index c9a31e6faab2..232e11b1526c 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -63,7 +63,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name); + pr_debug("INFTL: add_mtd for %s\n", mtd->name); inftl = kzalloc(sizeof(*inftl), GFP_KERNEL); @@ -131,7 +131,7 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev) { struct INFTLrecord *inftl = (void *)dev; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum); + pr_debug("INFTL: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); @@ -213,7 +213,7 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) u16 pot = inftl->LastFreeEUN; int silly = inftl->nb_blocks; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p," + pr_debug("INFTL: INFTL_findfreeblock(inftl=%p," "desperate=%d)\n", inftl, desperate); /* @@ -221,7 +221,7 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) * blocks completely. */ if (!desperate && inftl->numfreeEUNs < 2) { - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free " + pr_debug("INFTL: there are too few free " "EUNs (%d)\n", inftl->numfreeEUNs); return BLOCK_NIL; } @@ -257,7 +257,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned struct inftl_oob oob; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d," + pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d," "pending=%d)\n", inftl, thisVUC, pendingblock); memset(BlockMap, 0xff, sizeof(BlockMap)); @@ -321,7 +321,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * Chain, and the Erase Unit into which we are supposed to be copying. * Go for it. */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n", + pr_debug("INFTL: folding chain %d into unit %d\n", thisVUC, targetEUN); for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) { @@ -353,7 +353,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned (block * SECTORSIZE), SECTORSIZE, &retlen, movebuf); if (ret != -EIO) - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " + pr_debug("INFTL: error went " "away on retry?\n"); } memset(&oob, 0xff, sizeof(struct inftl_oob)); @@ -370,7 +370,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * is important, by doing oldest first if we crash/reboot then it * it is relatively simple to clean up the mess). */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n", + pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC); for (;;) { @@ -419,7 +419,7 @@ static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) u16 ChainLength = 0, thislen; u16 chain, EUN; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p," + pr_debug("INFTL: INFTL_makefreeblock(inftl=%p," "pending=%d)\n", inftl, pendingblock); for (chain = 0; chain < inftl->nb_blocks; chain++) { @@ -482,7 +482,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) size_t retlen; int silly, silly2 = 3; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p," + pr_debug("INFTL: INFTL_findwriteunit(inftl=%p," "block=%d)\n", inftl, block); do { @@ -499,7 +499,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) blockofs, 8, &retlen, (char *)&bci); status = bci.Status | bci.Status1; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " + pr_debug("INFTL: status of block %d in " "EUN %d is %x\n", block , writeEUN, status); switch(status) { @@ -553,7 +553,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) * Hopefully we free something, lets try again. * This time we are desperate... */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 " + pr_debug("INFTL: using desperate==1 " "to find free EUN to accommodate write to " "VUC %d\n", thisVUC); writeEUN = INFTL_findfreeblock(inftl, 1); @@ -645,7 +645,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) struct inftl_bci bci; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p," + pr_debug("INFTL: INFTL_trydeletechain(inftl=%p," "thisVUC=%d)\n", inftl, thisVUC); memset(BlockUsed, 0, sizeof(BlockUsed)); @@ -709,7 +709,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) * For each block in the chain free it and make it available * for future use. Erase from the oldest unit first. */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC); + pr_debug("INFTL: deleting empty VUC %d\n", thisVUC); for (;;) { u16 *prevEUN = &inftl->VUtable[thisVUC]; @@ -717,7 +717,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) /* If the chain is all gone already, we're done */ if (thisEUN == BLOCK_NIL) { - DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); + pr_debug("INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); return; } @@ -729,7 +729,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) thisEUN = *prevEUN; } - DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", + pr_debug("Deleting EUN %d from VUC %d\n", thisEUN, thisVUC); if (INFTL_formatblock(inftl, thisEUN) < 0) { @@ -765,7 +765,7 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block) size_t retlen; struct inftl_bci bci; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p," + pr_debug("INFTL: INFTL_deleteblock(inftl=%p," "block=%d)\n", inftl, block); while (thisEUN < inftl->nb_blocks) { @@ -824,7 +824,7 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, struct inftl_oob oob; char *p, *pend; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld," + pr_debug("INFTL: inftl_writeblock(inftl=%p,block=%ld," "buffer=%p)\n", inftl, block, buffer); /* Is block all zero? */ @@ -874,7 +874,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, struct inftl_bci bci; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld," + pr_debug("INFTL: inftl_readblock(inftl=%p,block=%ld," "buffer=%p)\n", inftl, block, buffer); while (thisEUN < inftl->nb_blocks) { diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 104052e774b0..d969c2d5d62b 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -53,7 +53,7 @@ static int find_boot_record(struct INFTLrecord *inftl) struct INFTLPartition *ip; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=%p)\n", inftl); + pr_debug("INFTL: find_boot_record(inftl=%p)\n", inftl); /* * Assume logical EraseSize == physical erasesize for starting the @@ -385,7 +385,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block) struct mtd_info *mtd = inftl->mbd.mtd; int physblock; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p," + pr_debug("INFTL: INFTL_formatblock(inftl=%p," "block=%d)\n", inftl, block); memset(instr, 0, sizeof(struct erase_info)); @@ -555,7 +555,7 @@ int INFTL_mount(struct INFTLrecord *s) int i; u8 *ANACtable, ANAC; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=%p)\n", s); + pr_debug("INFTL: INFTL_mount(inftl=%p)\n", s); /* Search for INFTL MediaHeader and Spare INFTL Media Header */ if (find_boot_record(s) < 0) { @@ -585,7 +585,7 @@ int INFTL_mount(struct INFTLrecord *s) * NOTEXPLORED state. Then at the end we will try to format it and * mark it as free. */ - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n"); + pr_debug("INFTL: pass 1, explore each unit\n"); for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) { if (s->PUtable[first_block] != BLOCK_NOTEXPLORED) continue; @@ -727,7 +727,7 @@ int INFTL_mount(struct INFTLrecord *s) * possible because we don't update the previous pointers when * we fold chains. No big deal, just fix them up in PUtable. */ - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n"); + pr_debug("INFTL: pass 2, validate virtual chains\n"); for (logical_block = 0; logical_block < s->numvunits; logical_block++) { block = s->VUtable[logical_block]; last_block = BLOCK_NIL; @@ -785,7 +785,7 @@ int INFTL_mount(struct INFTLrecord *s) s->numfreeEUNs = 0; s->LastFreeEUN = BLOCK_NIL; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n"); + pr_debug("INFTL: pass 3, format unused blocks\n"); for (block = s->firstEUN; block <= s->lastEUN; block++) { if (s->PUtable[block] == BLOCK_NOTEXPLORED) { printk("INFTL: unreferenced block %d, formatting it\n", diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 1976b6c0508d..7c1dc908a174 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -119,7 +119,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) if (mtdblk->cache_state != STATE_DIRTY) return 0; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " + pr_debug("mtdblock: writing cached data for \"%s\" " "at 0x%lx, size 0x%x\n", mtd->name, mtdblk->cache_offset, mtdblk->cache_size); @@ -148,7 +148,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, size_t retlen; int ret; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", + pr_debug("mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); if (!sect_size) @@ -218,7 +218,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, size_t retlen; int ret; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", + pr_debug("mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); if (!sect_size) @@ -283,7 +283,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); - DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); + pr_debug("mtdblock_open\n"); mutex_lock(&mtdblks_lock); if (mtdblk->count) { @@ -303,7 +303,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) mutex_unlock(&mtdblks_lock); - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + pr_debug("ok\n"); return 0; } @@ -312,7 +312,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); - DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); + pr_debug("mtdblock_release\n"); mutex_lock(&mtdblks_lock); @@ -329,7 +329,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) mutex_unlock(&mtdblks_lock); - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + pr_debug("ok\n"); return 0; } diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index e197192331f9..22526e98b85b 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -86,7 +86,7 @@ static int mtd_open(struct inode *inode, struct file *file) struct mtd_file_info *mfi; struct inode *mtd_ino; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); + pr_debug("MTD_open\n"); /* You can't open the RO devices RW */ if ((file->f_mode & FMODE_WRITE) && (minor & 1)) @@ -151,7 +151,7 @@ static int mtd_close(struct inode *inode, struct file *file) struct mtd_file_info *mfi = file->private_data; struct mtd_info *mtd = mfi->mtd; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); + pr_debug("MTD_close\n"); /* Only sync if opened RW */ if ((file->f_mode & FMODE_WRITE) && mtd->sync) @@ -195,7 +195,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t size_t size = count; char *kbuf; - DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); + pr_debug("MTD_read\n"); if (*ppos + count > mtd->size) count = mtd->size - *ppos; @@ -278,7 +278,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count int ret=0; int len; - DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); + pr_debug("MTD_write\n"); if (*ppos == mtd->size) return -ENOSPC; @@ -570,7 +570,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) u_long size; struct mtd_info_user info; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); + pr_debug("MTD_ioctl\n"); size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; if (cmd & IOC_IN) { diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index f9cc2d2cb5cb..887aed02aa2e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -362,7 +362,7 @@ int add_mtd_device(struct mtd_info *mtd) MTD_DEVT(i) + 1, NULL, "mtd%dro", i); - DEBUG(0, "mtd: Giving out device %d to %s\n", i, mtd->name); + pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); /* No need to get a refcount on the module containing the notifier, since we hold the mtd_table_mutex */ list_for_each_entry(not, &mtd_notifiers, list) diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 16b02a1fc100..80fe5dcac111 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -26,12 +26,12 @@ static int get_sb_mtd_compare(struct super_block *sb, void *_mtd) struct mtd_info *mtd = _mtd; if (sb->s_mtd == mtd) { - DEBUG(2, "MTDSB: Match on device %d (\"%s\")\n", + pr_debug("MTDSB: Match on device %d (\"%s\")\n", mtd->index, mtd->name); return 1; } - DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", + pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name); return 0; } @@ -70,7 +70,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, goto already_mounted; /* fresh new superblock */ - DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n", + pr_debug("MTDSB: New superblock for device %d (\"%s\")\n", mtd->index, mtd->name); sb->s_flags = flags; @@ -87,7 +87,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, /* new mountpoint for an already mounted superblock */ already_mounted: - DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", + pr_debug("MTDSB: Device %d (\"%s\") is already mounted\n", mtd->index, mtd->name); put_mtd_device(mtd); return dget(sb->s_root); @@ -108,7 +108,7 @@ static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags, mtd = get_mtd_device(NULL, mtdnr); if (IS_ERR(mtd)) { - DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); + pr_debug("MTDSB: Device #%u doesn't appear to exist\n", mtdnr); return ERR_CAST(mtd); } @@ -131,7 +131,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, if (!dev_name) return ERR_PTR(-EINVAL); - DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); + pr_debug("MTDSB: dev_name \"%s\"\n", dev_name); /* the preferred way of mounting in future; especially when * CONFIG_BLOCK=n - we specify the underlying MTD device by number or @@ -142,7 +142,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, struct mtd_info *mtd; /* mount by MTD device name */ - DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n", + pr_debug("MTDSB: mtd:%%s, name \"%s\"\n", dev_name + 4); mtd = get_mtd_device_nm(dev_name + 4); @@ -163,7 +163,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, mtdnr = simple_strtoul(dev_name + 3, &endptr, 0); if (!*endptr) { /* It was a valid number */ - DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", + pr_debug("MTDSB: mtd%%d, mtdnr %d\n", mtdnr); return mount_mtd_nr(fs_type, flags, dev_name, data, @@ -179,10 +179,10 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, bdev = lookup_bdev(dev_name); if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); - DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); + pr_debug("MTDSB: lookup_bdev() returned %d\n", ret); return ERR_PTR(ret); } - DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); + pr_debug("MTDSB: lookup_bdev() returned 0\n"); ret = -EINVAL; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 4c2bb4a4bf0b..2fbfb71c237b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -349,7 +349,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) udelay(1); } if (max_retries < 0) - DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n", + pr_debug("%s: INT not set\n", __func__); } } @@ -370,7 +370,7 @@ static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) * waits for completion. */ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) { - DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); + pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq); writew(cmd, NFC_V1_V2_FLASH_CMD); writew(NFC_CMD, NFC_V1_V2_CONFIG2); @@ -386,7 +386,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) udelay(1); } if (max_retries < 0) - DEBUG(MTD_DEBUG_LEVEL0, "%s: RESET failed\n", + pr_debug("%s: RESET failed\n", __func__); } else { /* Wait for operation to complete */ @@ -410,7 +410,7 @@ static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast) * a NAND command. */ static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast) { - DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); + pr_debug("send_addr(host, 0x%x %d)\n", addr, islast); writew(addr, NFC_V1_V2_FLASH_ADDR); writew(NFC_ADDR, NFC_V1_V2_CONFIG2); @@ -560,8 +560,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT); if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - DEBUG(MTD_DEBUG_LEVEL0, - "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); + pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); return -1; } @@ -931,8 +930,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", + pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", command, column, page_addr); /* Reset command state information */ diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6a5271256245..7f2691f94322 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -113,21 +113,19 @@ static int check_offs_len(struct mtd_info *mtd, /* Start address must align on block boundary */ if (ofs & ((1 << chip->phys_erase_shift) - 1)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__); + pr_debug("%s: unaligned address\n", __func__); ret = -EINVAL; } /* Length must align on block boundary */ if (len & ((1 << chip->phys_erase_shift) - 1)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n", - __func__); + pr_debug("%s: length not block aligned\n", __func__); ret = -EINVAL; } /* Do not allow past end of device */ if (ofs + len > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n", - __func__); + pr_debug("%s: past end of device\n", __func__); ret = -EINVAL; } @@ -913,7 +911,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, status = chip->waitfunc(mtd, chip); /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", + pr_debug("%s: error status = 0x%08x\n", __func__, status); ret = -EIO; } @@ -935,7 +933,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) int chipnr; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", + pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) @@ -954,7 +952,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", + pr_debug("%s: device is write protected!\n", __func__); ret = -EIO; goto out; @@ -988,7 +986,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) int chipnr, status, page; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", + pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) @@ -1003,7 +1001,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", + pr_debug("%s: device is write protected!\n", __func__); status = MTD_ERASE_FAILED; ret = -EIO; @@ -1018,7 +1016,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) status = chip->waitfunc(mtd, chip); /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", + pr_debug("%s: error status = 0x%08x\n", __func__, status); ret = -EIO; goto out; @@ -1756,7 +1754,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, int len; uint8_t *buf = ops->oobbuf; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", + pr_debug("%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); stats = mtd->ecc_stats; @@ -1767,8 +1765,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, len = mtd->oobsize; if (unlikely(ops->ooboffs >= len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " - "outside oob\n", __func__); + pr_debug("%s: attempt to start read outside oob\n", + __func__); return -EINVAL; } @@ -1776,8 +1774,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, if (unlikely(from >= mtd->size || ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - (from >> chip->page_shift)) * len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end " - "of device\n", __func__); + pr_debug("%s: attempt to read beyond end of device\n", + __func__); return -EINVAL; } @@ -1856,8 +1854,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, /* Do not allow reads past end of device */ if (ops->datbuf && (from + ops->len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read " - "beyond end of device\n", __func__); + pr_debug("%s: attempt to read beyond end of device\n", + __func__); return -EINVAL; } @@ -2352,7 +2350,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, int chipnr, page, status, len; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, (int)ops->ooblen); if (ops->mode == MTD_OOB_AUTO) @@ -2362,14 +2360,14 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, /* Do not allow write past end of page */ if ((ops->ooboffs + ops->ooblen) > len) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write " - "past end of page\n", __func__); + pr_debug("%s: attempt to write past end of page\n", + __func__); return -EINVAL; } if (unlikely(ops->ooboffs >= len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start " - "write outside oob\n", __func__); + pr_debug("%s: attempt to start write outside oob\n", + __func__); return -EINVAL; } @@ -2378,8 +2376,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, ops->ooboffs + ops->ooblen > ((mtd->size >> chip->page_shift) - (to >> chip->page_shift)) * len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " - "end of device\n", __func__); + pr_debug("%s: attempt to write beyond end of device\n", + __func__); return -EINVAL; } @@ -2432,8 +2430,8 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, /* Do not allow writes past end of device */ if (ops->datbuf && (to + ops->len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " - "end of device\n", __func__); + pr_debug("%s: attempt to write beyond end of device\n", + __func__); return -EINVAL; } @@ -2522,9 +2520,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, unsigned int bbt_masked_page = 0xffffffff; loff_t len; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)instr->addr, - (unsigned long long)instr->len); + pr_debug("%s: start = 0x%012llx, len = %llu\n", + __func__, (unsigned long long)instr->addr, + (unsigned long long)instr->len); if (check_offs_len(mtd, instr->addr, instr->len)) return -EINVAL; @@ -2546,8 +2544,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", - __func__); + pr_debug("%s: device is write protected!\n", + __func__); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2598,8 +2596,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* See if block erase succeeded */ if (status & NAND_STATUS_FAIL) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, " - "page 0x%08x\n", __func__, page); + pr_debug("%s: failed erase, page 0x%08x\n", + __func__, page); instr->state = MTD_ERASE_FAILED; instr->fail_addr = ((loff_t)page << chip->page_shift); @@ -2659,9 +2657,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, if (!rewrite_bbt[chipnr]) continue; /* Update the BBT for chip */ - DEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " - "(%d:0x%0llx 0x%0x)\n", __func__, chipnr, - rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); + pr_debug("%s: nand_update_bbt (%d:0x%0llx 0x%0x)\n", + __func__, chipnr, rewrite_bbt[chipnr], + chip->bbt_td->pages[chipnr]); nand_update_bbt(mtd, rewrite_bbt[chipnr]); } @@ -2679,7 +2677,7 @@ static void nand_sync(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); + pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ nand_get_device(chip, mtd, FL_SYNCING); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index dba332327d4f..6aa8125772b8 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1383,8 +1383,9 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int)(offs >> (this->bbt_erase_shift - 1)); res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); + pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " + "(block %d) 0x%02x\n", + (unsigned int)offs, block >> 1, res); switch ((int)res) { case 0x00: diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index 0f931e757116..16cca9b99052 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -93,7 +93,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); /* else error in ecc, no action needed */ - DEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", + pr_debug("%s: corrected bitflip %u\n", __func__, errloc[i]); } } else if (count < 0) { diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index c5e33fdcbc86..81e6bc0c9048 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -741,12 +741,12 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ case 1: /* Uncorrectable error */ - DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); + pr_debug("ECC UNCORRECTED_ERROR 1\n"); return -1; case 11: /* UN-Correctable error */ - DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\n"); + pr_debug("ECC UNCORRECTED_ERROR B\n"); return -1; case 12: @@ -763,7 +763,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; - DEBUG(MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at " + pr_debug("Correcting single bit ECC error at " "offset: %d, bit: %d\n", find_byte, find_bit); page_data[find_byte] ^= (1 << find_bit); @@ -776,7 +776,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ ecc_data2[2] == 0) return 0; } - DEBUG(MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); + pr_debug("UNCORRECTED_ERROR default\n"); return -1; } } diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 33fe922b972c..f309addc2fa0 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -380,7 +380,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha /* Let the library code do its magic. */ res = decode_rs8(rs_decoder, (uint8_t *) buf, par, 512, syn, 0, NULL, 0xff, NULL); if (res > 0) { - DEBUG(MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); + pr_debug("rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); } return res; } diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index f3b3239746c8..93d6fc68b892 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -63,7 +63,7 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name); + pr_debug("NFTL: add_mtd for %s\n", mtd->name); nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL); @@ -130,7 +130,7 @@ static void nftl_remove_dev(struct mtd_blktrans_dev *dev) { struct NFTLrecord *nftl = (void *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum); + pr_debug("NFTL: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); kfree(nftl->ReplUnitTable); @@ -218,7 +218,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) /* Normally, we force a fold to happen before we run out of free blocks completely */ if (!desperate && nftl->numfreeEUNs < 2) { - DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n"); + pr_debug("NFTL_findfreeblock: there are too few free EUNs\n"); return BLOCK_NIL; } @@ -289,8 +289,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (block == 2) { foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; if (foldmark == FOLD_MARK_IN_PROGRESS) { - DEBUG(MTD_DEBUG_LEVEL1, - "Write Inhibited on EUN %d\n", thisEUN); + pr_debug("Write Inhibited on EUN %d\n", thisEUN); inplace = 0; } else { /* There's no other reason not to do inplace, @@ -355,7 +354,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (BlockLastState[block] != SECTOR_FREE && BlockMap[block] != BLOCK_NIL && BlockMap[block] != targetEUN) { - DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, " + pr_debug("Setting inplace to 0. VUC %d, " "block %d was %x lastEUN, " "and is in EUN %d (%s) %d\n", thisVUC, block, BlockLastState[block], @@ -371,14 +370,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) && BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] != SECTOR_FREE) { - DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. " + pr_debug("Pending write not free in EUN %d. " "Folding out of place.\n", targetEUN); inplace = 0; } } if (!inplace) { - DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " + pr_debug("Cannot fold Virtual Unit Chain %d in place. " "Trying out-of-place\n", thisVUC); /* We need to find a targetEUN to fold into. */ targetEUN = NFTL_findfreeblock(nftl, 1); @@ -408,7 +407,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p and the Erase Unit into which we are supposed to be copying. Go for it. */ - DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN); + pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN); for (block = 0; block < nftl->EraseSize / 512 ; block++) { unsigned char movebuf[512]; int ret; @@ -455,7 +454,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p has duplicate chains, we need to free one of the chains because it's not necessary any more. */ thisEUN = nftl->EUNtable[thisVUC]; - DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); + pr_debug("Want to erase\n"); /* For each block in the old chain (except the targetEUN of course), free it and make it available for future use */ @@ -568,7 +567,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) (writeEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci); - DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", + pr_debug("Status of block %d in EUN %d is %x\n", block , writeEUN, le16_to_cpu(bci.Status)); status = bci.Status | bci.Status1; @@ -621,7 +620,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) but they are reserved for when we're desperate. Well, now we're desperate. */ - DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC); + pr_debug("Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC); writeEUN = NFTL_findfreeblock(nftl, 1); } if (writeEUN == BLOCK_NIL) { diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 30c652c071e8..b07b05259c92 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1122,7 +1122,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0; int writesize = this->writesize; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int) from, (int) len); if (ops->mode == MTD_OOB_AUTO) @@ -1226,7 +1226,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0, boundary = 0; int writesize = this->writesize; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int) from, (int) len); if (ops->mode == MTD_OOB_AUTO) @@ -1357,7 +1357,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, from += ops->ooboffs; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int) from, (int) len); /* Initialize return length value */ @@ -1576,7 +1576,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, size_t len = ops->ooblen; u_char *buf = ops->oobbuf; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %zi\n", + pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int) from, len); /* Initialize return value */ @@ -1750,7 +1750,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, /* Wait for any existing operation to clear */ onenand_panic_wait(mtd); - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ @@ -1883,7 +1883,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; int ret = 0, cmd; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ @@ -2078,7 +2078,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, to += ops->ooboffs; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ @@ -2489,7 +2489,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) struct mtd_erase_region_info *region = NULL; loff_t region_offset = 0; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__, + pr_debug("%s: start=0x%012llx, len=%llu\n", __func__, (unsigned long long) instr->addr, (unsigned long long) instr->len); /* Do not allow erase past end of device */ @@ -2558,7 +2558,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) */ static void onenand_sync(struct mtd_info *mtd) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); + pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_SYNCING); diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 09a7d1fb511d..3b9a2a9573c6 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -153,7 +153,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int) (onenand_block(this, offs) << 1); res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", + pr_debug("onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", (unsigned int) offs, block >> 1, res); switch ((int) res) { diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 00d1405af50b..5f917f0a9609 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -135,8 +135,7 @@ static int get_valid_cis_sector(struct mtd_info *mtd) /* Found */ cis_sector = (int)(offset >> SECTOR_SHIFT); } else { - DEBUG(MTD_DEBUG_LEVEL1, - "SSFDC_RO: CIS/IDI sector not found" + pr_debug("SSFDC_RO: CIS/IDI sector not found" " on %s (mtd%d)\n", mtd->name, mtd->index); } @@ -221,8 +220,7 @@ static int get_logical_address(uint8_t *oob_buf) block_address >>= 1; if (get_parity(block_address, 10) != parity) { - DEBUG(MTD_DEBUG_LEVEL0, - "SSFDC_RO: logical address field%d" + pr_debug("SSFDC_RO: logical address field%d" "parity error(0x%04X)\n", j+1, block_address); } else { @@ -235,7 +233,7 @@ static int get_logical_address(uint8_t *oob_buf) if (!ok) block_address = -2; - DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n", + pr_debug("SSFDC_RO: get_logical_address() %d\n", block_address); return block_address; @@ -249,7 +247,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) int ret, block_address, phys_block; struct mtd_info *mtd = ssfdc->mbd.mtd; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n", + pr_debug("SSFDC_RO: build_block_map() nblks=%d (%luK)\n", ssfdc->map_len, (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024); @@ -262,8 +260,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) ret = read_raw_oob(mtd, offset, oob_buf); if (ret < 0) { - DEBUG(MTD_DEBUG_LEVEL0, - "SSFDC_RO: mtd read_oob() failed at %lu\n", + pr_debug("SSFDC_RO: mtd read_oob() failed at %lu\n", offset); return -1; } @@ -279,8 +276,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) ssfdc->logic_block_map[block_address] = (unsigned short)phys_block; - DEBUG(MTD_DEBUG_LEVEL2, - "SSFDC_RO: build_block_map() phys_block=%d," + pr_debug("SSFDC_RO: build_block_map() phys_block=%d," "logic_block_addr=%d, zone=%d\n", phys_block, block_address, zone_index); } @@ -316,8 +312,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->erase_size = mtd->erasesize; ssfdc->map_len = (u32)mtd->size / mtd->erasesize; - DEBUG(MTD_DEBUG_LEVEL1, - "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", + pr_debug("SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len, DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE)); @@ -328,7 +323,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) / ((long)ssfdc->sectors * (long)ssfdc->heads)); - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", + pr_debug("SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", ssfdc->cylinders, ssfdc->heads , ssfdc->sectors, (long)ssfdc->cylinders * (long)ssfdc->heads * (long)ssfdc->sectors); @@ -365,7 +360,7 @@ static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev) { struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum); + pr_debug("SSFDC_RO: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); kfree(ssfdc->logic_block_map); @@ -381,8 +376,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, offset = (int)(logic_sect_no % sectors_per_block); block_address = (int)(logic_sect_no / sectors_per_block); - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d," + pr_debug("SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d," " block_addr=%d\n", logic_sect_no, sectors_per_block, offset, block_address); @@ -391,8 +385,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, block_address = ssfdc->logic_block_map[block_address]; - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n", + pr_debug("SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n", block_address); if (block_address < 0xffff) { @@ -401,8 +394,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, sect_no = (unsigned long)block_address * sectors_per_block + offset; - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", + pr_debug("SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", sect_no); if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0) @@ -418,7 +410,7 @@ static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n", + pr_debug("SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n", ssfdc->cylinders, ssfdc->heads, ssfdc->sectors); geo->heads = ssfdc->heads; From 0a32a10264d151bc2d1616d69edaf915aa728698 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:10 -0700 Subject: [PATCH 0309/1596] mtd: cleanup style on pr_debug messages Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/chips/cfi_cmdset_0002.c | 10 ++++----- drivers/mtd/devices/m25p80.c | 33 ++++++++++++--------------- drivers/mtd/devices/mtd_dataflash.c | 18 +++++++-------- drivers/mtd/inftlcore.c | 35 +++++++++++++---------------- drivers/mtd/inftlmount.c | 3 +-- drivers/mtd/nand/mxc_nand.c | 6 ++--- drivers/mtd/nand/nand_bch.c | 4 ++-- drivers/mtd/nand/omap2.c | 4 ++-- drivers/mtd/onenand/onenand_base.c | 31 ++++++++++++------------- 9 files changed, 66 insertions(+), 78 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 2302cc00b4a9..8d70895a58d6 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -440,8 +440,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) mtd->writesize = 1; mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; - pr_debug("MTD %s(): write buffer size %d\n", - __func__, mtd->writebufsize); + pr_debug("MTD %s(): write buffer size %d\n", __func__, + mtd->writebufsize); mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; @@ -1798,8 +1798,7 @@ static int do_atmel_lock(struct map_info *map, struct flchip *chip, goto out_unlock; chip->state = FL_LOCKING; - pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", - __func__, adr, len); + pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1834,8 +1833,7 @@ static int do_atmel_unlock(struct map_info *map, struct flchip *chip, goto out_unlock; chip->state = FL_UNLOCKING; - pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", - __func__, adr, len); + pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 6417bd6b36ff..e6ba034c45bc 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -208,9 +208,8 @@ static int wait_till_ready(struct m25p *flash) */ static int erase_chip(struct m25p *flash) { - pr_debug("%s: %s %lldKiB\n", - dev_name(&flash->spi->dev), __func__, - (long long)(flash->mtd.size >> 10)); + pr_debug("%s: %s %lldKiB\n", dev_name(&flash->spi->dev), __func__, + (long long)(flash->mtd.size >> 10)); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -249,9 +248,8 @@ static int m25p_cmdsz(struct m25p *flash) */ static int erase_sector(struct m25p *flash, u32 offset) { - pr_debug("%s: %s %dKiB at 0x%08x\n", - dev_name(&flash->spi->dev), __func__, - flash->mtd.erasesize / 1024, offset); + pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev), + __func__, flash->mtd.erasesize / 1024, offset); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -285,9 +283,9 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) u32 addr,len; uint32_t rem; - pr_debug("%s: %s %s 0x%llx, len %lld\n", - dev_name(&flash->spi->dev), __func__, "at", - (long long)instr->addr, (long long)instr->len); + pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev), + __func__, (long long)instr->addr, + (long long)instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) @@ -347,9 +345,8 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer t[2]; struct spi_message m; - pr_debug("%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "from", - (u32)from, len); + pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)from, len); /* sanity checks */ if (!len) @@ -416,9 +413,8 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_transfer t[2]; struct spi_message m; - pr_debug("%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "to", - (u32)to, len); + pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)to, len); *retlen = 0; @@ -509,9 +505,8 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t actual; int cmd_sz, ret; - pr_debug("%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "to", - (u32)to, len); + pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)to, len); *retlen = 0; @@ -788,7 +783,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) tmp = spi_write_then_read(spi, &code, 1, id, 5); if (tmp < 0) { pr_debug("%s: error %d reading JEDEC ID\n", - dev_name(&spi->dev), tmp); + dev_name(&spi->dev), tmp); return ERR_PTR(tmp); } jedec = id[0]; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index f409aef58ed2..d75c7af18a63 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -249,8 +249,8 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, uint8_t *command; int status; - pr_debug("%s: read 0x%x..0x%x\n", - dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len)); + pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev), + (unsigned)from, (unsigned)(from + len)); *retlen = 0; @@ -384,7 +384,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, status = spi_sync(spi, &msg); if (status < 0) - pr_debug("%s: xfer %u -> %d \n", + pr_debug("%s: xfer %u -> %d\n", dev_name(&spi->dev), addr, status); (void) dataflash_waitready(priv->spi); @@ -406,7 +406,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, status = spi_sync(spi, &msg); spi_transfer_del(x + 1); if (status < 0) - pr_debug("%s: pgm %u/%u -> %d \n", + pr_debug("%s: pgm %u/%u -> %d\n", dev_name(&spi->dev), addr, writelen, status); (void) dataflash_waitready(priv->spi); @@ -426,7 +426,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, status = spi_sync(spi, &msg); if (status < 0) - pr_debug("%s: compare %u -> %d \n", + pr_debug("%s: compare %u -> %d\n", dev_name(&spi->dev), addr, status); status = dataflash_waitready(priv->spi); @@ -906,14 +906,14 @@ static int __devinit dataflash_probe(struct spi_device *spi) break; /* obsolete AT45DB1282 not (yet?) supported */ default: - pr_debug("%s: unsupported device (%x)\n", - dev_name(&spi->dev), status & 0x3c); + pr_debug("%s: unsupported device (%x)\n", dev_name(&spi->dev), + status & 0x3c); status = -ENODEV; } if (status < 0) - pr_debug("%s: add_dataflash --> %d\n", - dev_name(&spi->dev), status); + pr_debug("%s: add_dataflash --> %d\n", dev_name(&spi->dev), + status); return status; } diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 232e11b1526c..21aa981e42cd 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -213,16 +213,16 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) u16 pot = inftl->LastFreeEUN; int silly = inftl->nb_blocks; - pr_debug("INFTL: INFTL_findfreeblock(inftl=%p," - "desperate=%d)\n", inftl, desperate); + pr_debug("INFTL: INFTL_findfreeblock(inftl=%p,desperate=%d)\n", + inftl, desperate); /* * Normally, we force a fold to happen before we run out of free * blocks completely. */ if (!desperate && inftl->numfreeEUNs < 2) { - pr_debug("INFTL: there are too few free " - "EUNs (%d)\n", inftl->numfreeEUNs); + pr_debug("INFTL: there are too few free EUNs (%d)\n", + inftl->numfreeEUNs); return BLOCK_NIL; } @@ -257,8 +257,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned struct inftl_oob oob; size_t retlen; - pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d," - "pending=%d)\n", inftl, thisVUC, pendingblock); + pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,pending=%d)\n", + inftl, thisVUC, pendingblock); memset(BlockMap, 0xff, sizeof(BlockMap)); memset(BlockDeleted, 0, sizeof(BlockDeleted)); @@ -321,8 +321,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * Chain, and the Erase Unit into which we are supposed to be copying. * Go for it. */ - pr_debug("INFTL: folding chain %d into unit %d\n", - thisVUC, targetEUN); + pr_debug("INFTL: folding chain %d into unit %d\n", thisVUC, targetEUN); for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) { unsigned char movebuf[SECTORSIZE]; @@ -353,8 +352,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned (block * SECTORSIZE), SECTORSIZE, &retlen, movebuf); if (ret != -EIO) - pr_debug("INFTL: error went " - "away on retry?\n"); + pr_debug("INFTL: error went away on retry?\n"); } memset(&oob, 0xff, sizeof(struct inftl_oob)); oob.b.Status = oob.b.Status1 = SECTOR_USED; @@ -370,8 +368,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * is important, by doing oldest first if we crash/reboot then it * it is relatively simple to clean up the mess). */ - pr_debug("INFTL: want to erase virtual chain %d\n", - thisVUC); + pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC); for (;;) { /* Find oldest unit in chain. */ @@ -482,8 +479,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) size_t retlen; int silly, silly2 = 3; - pr_debug("INFTL: INFTL_findwriteunit(inftl=%p," - "block=%d)\n", inftl, block); + pr_debug("INFTL: INFTL_findwriteunit(inftl=%p,block=%d)\n", + inftl, block); do { /* @@ -499,8 +496,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) blockofs, 8, &retlen, (char *)&bci); status = bci.Status | bci.Status1; - pr_debug("INFTL: status of block %d in " - "EUN %d is %x\n", block , writeEUN, status); + pr_debug("INFTL: status of block %d in EUN %d is %x\n", + block , writeEUN, status); switch(status) { case SECTOR_FREE: @@ -553,9 +550,9 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) * Hopefully we free something, lets try again. * This time we are desperate... */ - pr_debug("INFTL: using desperate==1 " - "to find free EUN to accommodate write to " - "VUC %d\n", thisVUC); + pr_debug("INFTL: using desperate==1 to find free EUN " + "to accommodate write to VUC %d\n", + thisVUC); writeEUN = INFTL_findfreeblock(inftl, 1); if (writeEUN == BLOCK_NIL) { /* diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index d969c2d5d62b..bd82b04ec8f2 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -385,8 +385,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block) struct mtd_info *mtd = inftl->mbd.mtd; int physblock; - pr_debug("INFTL: INFTL_formatblock(inftl=%p," - "block=%d)\n", inftl, block); + pr_debug("INFTL: INFTL_formatblock(inftl=%p,block=%d)\n", inftl, block); memset(instr, 0, sizeof(struct erase_info)); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 2fbfb71c237b..ebeb84316ecd 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -349,8 +349,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) udelay(1); } if (max_retries < 0) - pr_debug("%s: INT not set\n", - __func__); + pr_debug("%s: INT not set\n", __func__); } } @@ -386,8 +385,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) udelay(1); } if (max_retries < 0) - pr_debug("%s: RESET failed\n", - __func__); + pr_debug("%s: RESET failed\n", __func__); } else { /* Wait for operation to complete */ wait_op_done(host, useirq); diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index 16cca9b99052..3803e0bba23b 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -93,8 +93,8 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); /* else error in ecc, no action needed */ - pr_debug("%s: corrected bitflip %u\n", - __func__, errloc[i]); + pr_debug("%s: corrected bitflip %u\n", __func__, + errloc[i]); } } else if (count < 0) { printk(KERN_ERR "ecc unrecoverable error\n"); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 81e6bc0c9048..19b283f2c80c 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -763,8 +763,8 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; - pr_debug("Correcting single bit ECC error at " - "offset: %d, bit: %d\n", find_byte, find_bit); + pr_debug("Correcting single bit ECC error at offset: " + "%d, bit: %d\n", find_byte, find_bit); page_data[find_byte] ^= (1 << find_bit); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index b07b05259c92..de98791f8101 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1122,8 +1122,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0; int writesize = this->writesize; - pr_debug("%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); if (ops->mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; @@ -1226,8 +1226,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0, boundary = 0; int writesize = this->writesize; - pr_debug("%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); if (ops->mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; @@ -1357,8 +1357,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, from += ops->ooboffs; - pr_debug("%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); /* Initialize return length value */ ops->oobretlen = 0; @@ -1576,8 +1576,8 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, size_t len = ops->ooblen; u_char *buf = ops->oobbuf; - pr_debug("%s: from = 0x%08x, len = %zi\n", - __func__, (unsigned int) from, len); + pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from, + len); /* Initialize return value */ ops->oobretlen = 0; @@ -1750,8 +1750,8 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, /* Wait for any existing operation to clear */ onenand_panic_wait(mtd); - pr_debug("%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; @@ -1883,8 +1883,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; int ret = 0, cmd; - pr_debug("%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ ops->retlen = 0; @@ -2078,8 +2078,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, to += ops->ooboffs; - pr_debug("%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ ops->oobretlen = 0; @@ -2490,7 +2490,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) loff_t region_offset = 0; pr_debug("%s: start=0x%012llx, len=%llu\n", __func__, - (unsigned long long) instr->addr, (unsigned long long) instr->len); + (unsigned long long)instr->addr, + (unsigned long long)instr->len); /* Do not allow erase past end of device */ if (unlikely((len + addr) > mtd->size)) { From e6453521edcaa6f130946b5f4fcaf28dbc02f2ed Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:11 -0700 Subject: [PATCH 0310/1596] mtd: pcmciamtd: remove custom DEBUG() function We don't need a custom DEBUG() macro here. Just use the built-in kernel code with dynamic debugging features. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/pcmciamtd.c | 120 +++++++++++++++-------------------- 1 file changed, 52 insertions(+), 68 deletions(-) diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index bbe168b65c26..afa9bd81220b 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -22,22 +22,6 @@ #include #include -#ifdef CONFIG_MTD_DEBUG -static int debug = CONFIG_MTD_DEBUG_VERBOSE; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy"); -#undef DEBUG -#define DEBUG(n, format, arg...) \ - if (n <= debug) { \ - printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \ - } - -#else -#undef DEBUG -#define DEBUG(n, arg...) -static const int debug = 0; -#endif - #define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg) #define DRIVER_DESC "PCMCIA Flash memory card driver" @@ -105,13 +89,13 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) int ret; if (!pcmcia_dev_present(dev->p_dev)) { - DEBUG(1, "device removed"); + pr_debug("device removed\n"); return 0; } offset = to & ~(dev->win_size-1); if (offset != dev->offset) { - DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x", + pr_debug("Remapping window from 0x%8.8x to 0x%8.8x\n", dev->offset, offset); ret = pcmcia_map_mem_page(dev->p_dev, win, offset); if (ret != 0) @@ -132,7 +116,7 @@ static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs) return d; d.x[0] = readb(addr); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02lx", ofs, addr, d.x[0]); + pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n", ofs, addr, d.x[0]); return d; } @@ -147,7 +131,7 @@ static map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs) return d; d.x[0] = readw(addr); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04lx", ofs, addr, d.x[0]); + pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n", ofs, addr, d.x[0]); return d; } @@ -157,7 +141,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; unsigned long win_size = dev->win_size; - DEBUG(3, "to = %p from = %lu len = %zd", to, from, len); + pr_debug("to = %p from = %lu len = %zd\n", to, from, len); while(len) { int toread = win_size - (from & (win_size-1)); caddr_t addr; @@ -169,7 +153,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long if(!addr) return; - DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread); + pr_debug("memcpy from %p to %p len = %d\n", addr, to, toread); memcpy_fromio(to, addr, toread); len -= toread; to += toread; @@ -185,7 +169,7 @@ static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long if(!addr) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02lx", adr, addr, d.x[0]); + pr_debug("adr = 0x%08lx (%p) data = 0x%02lx\n", adr, addr, d.x[0]); writeb(d.x[0], addr); } @@ -196,7 +180,7 @@ static void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long if(!addr) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04lx", adr, addr, d.x[0]); + pr_debug("adr = 0x%08lx (%p) data = 0x%04lx\n", adr, addr, d.x[0]); writew(d.x[0], addr); } @@ -206,7 +190,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; unsigned long win_size = dev->win_size; - DEBUG(3, "to = %lu from = %p len = %zd", to, from, len); + pr_debug("to = %lu from = %p len = %zd\n", to, from, len); while(len) { int towrite = win_size - (to & (win_size-1)); caddr_t addr; @@ -218,7 +202,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v if(!addr) return; - DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite); + pr_debug("memcpy from %p to %p len = %d\n", from, addr, towrite); memcpy_toio(addr, from, towrite); len -= towrite; to += towrite; @@ -240,7 +224,7 @@ static map_word pcmcia_read8(struct map_info *map, unsigned long ofs) return d; d.x[0] = readb(win_base + ofs); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02lx", + pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n", ofs, win_base + ofs, d.x[0]); return d; } @@ -255,7 +239,7 @@ static map_word pcmcia_read16(struct map_info *map, unsigned long ofs) return d; d.x[0] = readw(win_base + ofs); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04lx", + pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n", ofs, win_base + ofs, d.x[0]); return d; } @@ -268,7 +252,7 @@ static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, if(DEV_REMOVED(map)) return; - DEBUG(3, "to = %p from = %lu len = %zd", to, from, len); + pr_debug("to = %p from = %lu len = %zd\n", to, from, len); memcpy_fromio(to, win_base + from, len); } @@ -280,7 +264,7 @@ static void pcmcia_write8(struct map_info *map, map_word d, unsigned long adr) if(DEV_REMOVED(map)) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02lx", + pr_debug("adr = 0x%08lx (%p) data = 0x%02lx\n", adr, win_base + adr, d.x[0]); writeb(d.x[0], win_base + adr); } @@ -293,7 +277,7 @@ static void pcmcia_write16(struct map_info *map, map_word d, unsigned long adr) if(DEV_REMOVED(map)) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04lx", + pr_debug("adr = 0x%08lx (%p) data = 0x%04lx\n", adr, win_base + adr, d.x[0]); writew(d.x[0], win_base + adr); } @@ -306,7 +290,7 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f if(DEV_REMOVED(map)) return; - DEBUG(3, "to = %lu from = %p len = %zd", to, from, len); + pr_debug("to = %lu from = %p len = %zd\n", to, from, len); memcpy_toio(win_base + to, from, len); } @@ -316,7 +300,7 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; struct pcmcia_device *link = dev->p_dev; - DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); + pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp); pcmcia_fixup_vpp(link, on ? dev->vpp : 0); } @@ -325,7 +309,7 @@ static void pcmciamtd_release(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; - DEBUG(3, "link = 0x%p", link); + pr_debug("link = 0x%p\n", link); if (link->resource[2]->end) { if(dev->win_base) { @@ -347,7 +331,7 @@ static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev, if (!pcmcia_parse_tuple(tuple, &parse)) { cistpl_format_t *t = &parse.format; (void)t; /* Shut up, gcc */ - DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", + pr_debug("Format type: %u, Error Detection: %u, offset = %u, length =%u\n", t->type, t->edc, t->offset, t->length); } return -ENOSPC; @@ -363,7 +347,7 @@ static int pcmciamtd_cistpl_jedec(struct pcmcia_device *p_dev, if (!pcmcia_parse_tuple(tuple, &parse)) { cistpl_jedec_t *t = &parse.jedec; for (i = 0; i < t->nid; i++) - DEBUG(2, "JEDEC: 0x%02x 0x%02x", + pr_debug("JEDEC: 0x%02x 0x%02x\n", t->id[i].mfr, t->id[i].info); } return -ENOSPC; @@ -382,14 +366,14 @@ static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev, if (pcmcia_parse_tuple(tuple, &parse)) return -EINVAL; - DEBUG(2, "Common memory:"); + pr_debug("Common memory:\n"); dev->pcmcia_map.size = t->dev[0].size; /* from here on: DEBUG only */ for (i = 0; i < t->ndev; i++) { - DEBUG(2, "Region %d, type = %u", i, t->dev[i].type); - DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp); - DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed); - DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size); + pr_debug("Region %d, type = %u\n", i, t->dev[i].type); + pr_debug("Region %d, wp = %u\n", i, t->dev[i].wp); + pr_debug("Region %d, speed = %u ns\n", i, t->dev[i].speed); + pr_debug("Region %d, size = %u bytes\n", i, t->dev[i].size); } return 0; } @@ -409,12 +393,12 @@ static int pcmciamtd_cistpl_geo(struct pcmcia_device *p_dev, dev->pcmcia_map.bankwidth = t->geo[0].buswidth; /* from here on: DEBUG only */ for (i = 0; i < t->ngeo; i++) { - DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth); - DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block); - DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block); - DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block); - DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition); - DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave); + pr_debug("region: %d bankwidth = %u\n", i, t->geo[i].buswidth); + pr_debug("region: %d erase_block = %u\n", i, t->geo[i].erase_block); + pr_debug("region: %d read_block = %u\n", i, t->geo[i].read_block); + pr_debug("region: %d write_block = %u\n", i, t->geo[i].write_block); + pr_debug("region: %d partition = %u\n", i, t->geo[i].partition); + pr_debug("region: %d interleave = %u\n", i, t->geo[i].interleave); } return 0; } @@ -432,7 +416,7 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev if (p_dev->prod_id[i]) strcat(dev->mtd_name, p_dev->prod_id[i]); } - DEBUG(2, "Found name: %s", dev->mtd_name); + pr_debug("Found name: %s\n", dev->mtd_name); } #ifdef CONFIG_MTD_DEBUG @@ -450,12 +434,12 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev if(force_size) { dev->pcmcia_map.size = force_size << 20; - DEBUG(2, "size forced to %dM", force_size); + pr_debug("size forced to %dM\n", force_size); } if(bankwidth) { dev->pcmcia_map.bankwidth = bankwidth; - DEBUG(2, "bankwidth forced to %d", bankwidth); + pr_debug("bankwidth forced to %d\n", bankwidth); } dev->pcmcia_map.name = dev->mtd_name; @@ -464,7 +448,7 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev *new_name = 1; } - DEBUG(1, "Device: Size: %lu Width:%d Name: %s", + pr_debug("Device: Size: %lu Width:%d Name: %s\n", dev->pcmcia_map.size, dev->pcmcia_map.bankwidth << 3, dev->mtd_name); } @@ -479,7 +463,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) static char *probes[] = { "jedec_probe", "cfi_probe" }; int new_name = 0; - DEBUG(3, "link=0x%p", link); + pr_debug("link=0x%p\n", link); card_settings(dev, link, &new_name); @@ -512,11 +496,11 @@ static int pcmciamtd_config(struct pcmcia_device *link) do { int ret; - DEBUG(2, "requesting window with size = %luKiB memspeed = %d", + pr_debug("requesting window with size = %luKiB memspeed = %d\n", (unsigned long) resource_size(link->resource[2]) >> 10, mem_speed); ret = pcmcia_request_window(link, link->resource[2], mem_speed); - DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); + pr_debug("ret = %d dev->win_size = %d\n", ret, dev->win_size); if(ret) { j++; link->resource[2]->start = 0; @@ -524,21 +508,21 @@ static int pcmciamtd_config(struct pcmcia_device *link) force_size << 20 : MAX_PCMCIA_ADDR; link->resource[2]->end >>= j; } else { - DEBUG(2, "Got window of size %luKiB", (unsigned long) + pr_debug("Got window of size %luKiB\n", (unsigned long) resource_size(link->resource[2]) >> 10); dev->win_size = resource_size(link->resource[2]); break; } } while (link->resource[2]->end >= 0x1000); - DEBUG(2, "dev->win_size = %d", dev->win_size); + pr_debug("dev->win_size = %d\n", dev->win_size); if(!dev->win_size) { dev_err(&dev->p_dev->dev, "Cannot allocate memory window\n"); pcmciamtd_release(link); return -ENODEV; } - DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); + pr_debug("Allocated a window of %dKiB\n", dev->win_size >> 10); /* Get write protect status */ dev->win_base = ioremap(link->resource[2]->start, @@ -549,7 +533,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) pcmciamtd_release(link); return -ENODEV; } - DEBUG(1, "mapped window dev = %p @ %pR, base = %p", + pr_debug("mapped window dev = %p @ %pR, base = %p\n", dev, link->resource[2], dev->win_base); dev->offset = 0; @@ -564,7 +548,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) } link->config_index = 0; - DEBUG(2, "Setting Configuration"); + pr_debug("Setting Configuration\n"); ret = pcmcia_enable_device(link); if (ret != 0) { if (dev->win_base) { @@ -580,17 +564,17 @@ static int pcmciamtd_config(struct pcmcia_device *link) mtd = do_map_probe("map_rom", &dev->pcmcia_map); } else { for(i = 0; i < ARRAY_SIZE(probes); i++) { - DEBUG(1, "Trying %s", probes[i]); + pr_debug("Trying %s\n", probes[i]); mtd = do_map_probe(probes[i], &dev->pcmcia_map); if(mtd) break; - DEBUG(1, "FAILED: %s", probes[i]); + pr_debug("FAILED: %s\n", probes[i]); } } if(!mtd) { - DEBUG(1, "Can not find an MTD"); + pr_debug("Can not find an MTD\n"); pcmciamtd_release(link); return -ENODEV; } @@ -617,7 +601,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) /* If the memory found is fits completely into the mapped PCMCIA window, use the faster non-remapping read/write functions */ if(mtd->size <= dev->win_size) { - DEBUG(1, "Using non remapping memory functions"); + pr_debug("Using non remapping memory functions\n"); dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base; if (dev->pcmcia_map.bankwidth == 1) { dev->pcmcia_map.read = pcmcia_read8; @@ -645,7 +629,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) static int pcmciamtd_suspend(struct pcmcia_device *dev) { - DEBUG(2, "EVENT_PM_RESUME"); + pr_debug("EVENT_PM_RESUME\n"); /* get_lock(link); */ @@ -654,7 +638,7 @@ static int pcmciamtd_suspend(struct pcmcia_device *dev) static int pcmciamtd_resume(struct pcmcia_device *dev) { - DEBUG(2, "EVENT_PM_SUSPEND"); + pr_debug("EVENT_PM_SUSPEND\n"); /* free_lock(link); */ @@ -666,7 +650,7 @@ static void pcmciamtd_detach(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; - DEBUG(3, "link=0x%p", link); + pr_debug("link=0x%p\n", link); if(dev->mtd_info) { mtd_device_unregister(dev->mtd_info); @@ -686,7 +670,7 @@ static int pcmciamtd_probe(struct pcmcia_device *link) /* Create new memory card device */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - DEBUG(1, "dev=0x%p", dev); + pr_debug("dev=0x%p\n", dev); dev->p_dev = link; link->priv = dev; @@ -755,7 +739,7 @@ static int __init init_pcmciamtd(void) static void __exit exit_pcmciamtd(void) { - DEBUG(1, DRIVER_DESC " unloading"); + pr_debug(DRIVER_DESC " unloading"); pcmcia_unregister_driver(&pcmciamtd_driver); } From 87ed114bb22bc65fce59c709e67599c1940efc7f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:12 -0700 Subject: [PATCH 0311/1596] mtd: remove CONFIG_MTD_DEBUG Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/Kconfig | 13 ------------- include/linux/mtd/mtd.h | 23 ----------------------- 2 files changed, 36 deletions(-) diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index cc02e2115efb..4925aa962af3 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -12,19 +12,6 @@ menuconfig MTD if MTD -config MTD_DEBUG - bool "Debugging" - help - This turns on low-level debugging for the entire MTD sub-system. - Normally, you should say 'N'. - -config MTD_DEBUG_VERBOSE - int "Debugging verbosity (0 = quiet, 3 = noisy)" - depends on MTD_DEBUG - default "0" - help - Determines the verbosity level of the MTD debugging messages. - config MTD_TESTS tristate "MTD tests support" depends on m diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 62d56f933b87..68ea22963a33 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -360,27 +360,4 @@ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size); void mtd_erase_callback(struct erase_info *instr); -/* - * Debugging macro and defines - */ -#define MTD_DEBUG_LEVEL0 (0) /* Quiet */ -#define MTD_DEBUG_LEVEL1 (1) /* Audible */ -#define MTD_DEBUG_LEVEL2 (2) /* Loud */ -#define MTD_DEBUG_LEVEL3 (3) /* Noisy */ - -#ifdef CONFIG_MTD_DEBUG -#define DEBUG(n, args...) \ - do { \ - if (n <= CONFIG_MTD_DEBUG_VERBOSE) \ - printk(KERN_INFO args); \ - } while(0) -#else /* CONFIG_MTD_DEBUG */ -#define DEBUG(n, args...) \ - do { \ - if (0) \ - printk(KERN_INFO args); \ - } while(0) - -#endif /* CONFIG_MTD_DEBUG */ - #endif /* __MTD_MTD_H__ */ From 278981c541b706a5b4b802890020689cd6ee7781 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:13 -0700 Subject: [PATCH 0312/1596] mtd: cleanup last uses of MTD_DEBUG config macros Some messages that were tied to CONFIG_MTD_DEBUG_VERBOSE can now simply be enabled using dynamic debugging features, if necessary. There's no need for special debugging functions here. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/inftlmount.c | 101 +++++++++++++++-------------------- drivers/mtd/maps/pcmciamtd.c | 4 -- 2 files changed, 43 insertions(+), 62 deletions(-) diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index bd82b04ec8f2..d19898cea550 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -139,24 +139,20 @@ static int find_boot_record(struct INFTLrecord *inftl) mh->FormatFlags = le32_to_cpu(mh->FormatFlags); mh->PercentUsed = le32_to_cpu(mh->PercentUsed); -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { - printk("INFTL: Media Header ->\n" - " bootRecordID = %s\n" - " NoOfBootImageBlocks = %d\n" - " NoOfBinaryPartitions = %d\n" - " NoOfBDTLPartitions = %d\n" - " BlockMultiplerBits = %d\n" - " FormatFlgs = %d\n" - " OsakVersion = 0x%x\n" - " PercentUsed = %d\n", - mh->bootRecordID, mh->NoOfBootImageBlocks, - mh->NoOfBinaryPartitions, - mh->NoOfBDTLPartitions, - mh->BlockMultiplierBits, mh->FormatFlags, - mh->OsakVersion, mh->PercentUsed); - } -#endif + pr_debug("INFTL: Media Header ->\n" + " bootRecordID = %s\n" + " NoOfBootImageBlocks = %d\n" + " NoOfBinaryPartitions = %d\n" + " NoOfBDTLPartitions = %d\n" + " BlockMultiplerBits = %d\n" + " FormatFlgs = %d\n" + " OsakVersion = 0x%x\n" + " PercentUsed = %d\n", + mh->bootRecordID, mh->NoOfBootImageBlocks, + mh->NoOfBinaryPartitions, + mh->NoOfBDTLPartitions, + mh->BlockMultiplierBits, mh->FormatFlags, + mh->OsakVersion, mh->PercentUsed); if (mh->NoOfBDTLPartitions == 0) { printk(KERN_WARNING "INFTL: Media Header sanity check " @@ -200,19 +196,15 @@ static int find_boot_record(struct INFTLrecord *inftl) ip->spareUnits = le32_to_cpu(ip->spareUnits); ip->Reserved0 = le32_to_cpu(ip->Reserved0); -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { - printk(" PARTITION[%d] ->\n" - " virtualUnits = %d\n" - " firstUnit = %d\n" - " lastUnit = %d\n" - " flags = 0x%x\n" - " spareUnits = %d\n", - i, ip->virtualUnits, ip->firstUnit, - ip->lastUnit, ip->flags, - ip->spareUnits); - } -#endif + pr_debug(" PARTITION[%d] ->\n" + " virtualUnits = %d\n" + " firstUnit = %d\n" + " lastUnit = %d\n" + " flags = 0x%x\n" + " spareUnits = %d\n", + i, ip->virtualUnits, ip->firstUnit, + ip->lastUnit, ip->flags, + ip->spareUnits); if (ip->Reserved0 != ip->firstUnit) { struct erase_info *instr = &inftl->instr; @@ -475,30 +467,30 @@ void INFTL_dumptables(struct INFTLrecord *s) { int i; - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); - printk("VUtable[%d] ->", s->nb_blocks); + pr_debug("VUtable[%d] ->", s->nb_blocks); for (i = 0; i < s->nb_blocks; i++) { if ((i % 8) == 0) - printk("\n%04x: ", i); - printk("%04x ", s->VUtable[i]); + pr_debug("\n%04x: ", i); + pr_debug("%04x ", s->VUtable[i]); } - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); - printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); + pr_debug("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); for (i = 0; i <= s->lastEUN; i++) { if ((i % 8) == 0) - printk("\n%04x: ", i); - printk("%04x ", s->PUtable[i]); + pr_debug("\n%04x: ", i); + pr_debug("%04x ", s->PUtable[i]); } - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); - printk("INFTL ->\n" + pr_debug("INFTL ->\n" " EraseSize = %d\n" " h/s/c = %d/%d/%d\n" " numvunits = %d\n" @@ -512,7 +504,7 @@ void INFTL_dumptables(struct INFTLrecord *s) s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs, s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks); - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); } @@ -520,25 +512,25 @@ void INFTL_dumpVUchains(struct INFTLrecord *s) { int logical, block, i; - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); - printk("INFTL Virtual Unit Chains:\n"); + pr_debug("INFTL Virtual Unit Chains:\n"); for (logical = 0; logical < s->nb_blocks; logical++) { block = s->VUtable[logical]; if (block > s->nb_blocks) continue; - printk(" LOGICAL %d --> %d ", logical, block); + pr_debug(" LOGICAL %d --> %d ", logical, block); for (i = 0; i < s->nb_blocks; i++) { if (s->PUtable[block] == BLOCK_NIL) break; block = s->PUtable[block]; - printk("%d ", block); + pr_debug("%d ", block); } - printk("\n"); + pr_debug("\n"); } - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); } @@ -716,10 +708,7 @@ int INFTL_mount(struct INFTLrecord *s) logical_block = BLOCK_NIL; } -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumptables(s); -#endif + INFTL_dumptables(s); /* * Second pass, check for infinite loops in chains. These are @@ -771,12 +760,8 @@ int INFTL_mount(struct INFTLrecord *s) } } -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumptables(s); - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumpVUchains(s); -#endif + INFTL_dumptables(s); + INFTL_dumpVUchains(s); /* * Third pass, format unreferenced blocks and init free block count. diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index afa9bd81220b..e8e9fec23553 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -321,7 +321,6 @@ static void pcmciamtd_release(struct pcmcia_device *link) } -#ifdef CONFIG_MTD_DEBUG static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev, tuple_t *tuple, void *priv_data) @@ -352,7 +351,6 @@ static int pcmciamtd_cistpl_jedec(struct pcmcia_device *p_dev, } return -ENOSPC; } -#endif static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev, tuple_t *tuple, @@ -419,10 +417,8 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev pr_debug("Found name: %s\n", dev->mtd_name); } -#ifdef CONFIG_MTD_DEBUG pcmcia_loop_tuple(p_dev, CISTPL_FORMAT, pcmciamtd_cistpl_format, NULL); pcmcia_loop_tuple(p_dev, CISTPL_JEDEC_C, pcmciamtd_cistpl_jedec, NULL); -#endif pcmcia_loop_tuple(p_dev, CISTPL_DEVICE, pcmciamtd_cistpl_device, dev); pcmcia_loop_tuple(p_dev, CISTPL_DEVICE_GEO, pcmciamtd_cistpl_geo, dev); From 022bba8a301c4218c358e949af339e55e3540d9c Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 Jul 2011 10:06:16 -0700 Subject: [PATCH 0313/1596] mtd: Kbuild: remove reference to MTD_PARTITIONS Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 891a9e644542..1b0d56cf4c47 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -254,7 +254,6 @@ config MTD_BCM963XX config MTD_LANTIQ tristate "Lantiq SoC NOR support" depends on LANTIQ - select MTD_PARTITIONS help Support for NOR flash attached to the Lantiq SoC's External Bus Unit. From 46a00d83ffb0d040f18068234e0eda8332c1e798 Mon Sep 17 00:00:00 2001 From: Jan Weitzel Date: Wed, 20 Jul 2011 09:28:04 +0200 Subject: [PATCH 0314/1596] mtd: use MTD_NAND_OMAP2 for OMAP4 use MTD_NAND_OMAP2 also for OMAP4 arch. testes with omap4430 Signed-off-by: Jan Weitzel Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/Kconfig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 17235d097774..7ec5b494583f 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -109,10 +109,11 @@ config MTD_NAND_AMS_DELTA Support for NAND flash on Amstrad E3 (Delta). config MTD_NAND_OMAP2 - tristate "NAND Flash device on OMAP2 and OMAP3" - depends on ARM && (ARCH_OMAP2 || ARCH_OMAP3) + tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4" + depends on ARM && (ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4) help - Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. + Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 + platforms. config MTD_NAND_IDS tristate From 92394b5c2be774425f255b5c7afbd8b19978fe12 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 20 Jul 2011 09:53:42 -0700 Subject: [PATCH 0315/1596] mtd: spelling fixes Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/ftl.c | 2 +- drivers/mtd/inftlmount.c | 2 +- drivers/mtd/mtdchar.c | 4 ++-- drivers/mtd/mtdconcat.c | 2 +- drivers/mtd/mtdcore.c | 2 +- drivers/mtd/mtdswap.c | 2 +- drivers/mtd/nftlmount.c | 26 +++++++++++++------------- drivers/mtd/sm_ftl.c | 16 ++++++++-------- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 95d77680ad15..c7382bb686c6 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -598,7 +598,7 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit, unit with the fewest erases, and usually pick the data unit with the most deleted blocks. But with a small probability, pick the oldest data unit instead. This means that we generally postpone - the next reclaimation as long as possible, but shuffle static + the next reclamation as long as possible, but shuffle static stuff around a bit for wear leveling. ======================================================================*/ diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index d19898cea550..2ff601f816ce 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -367,7 +367,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, * * Return: 0 when succeed, -1 on error. * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it necessary to check_free_sector after erasing ?? */ int INFTL_formatblock(struct INFTLrecord *inftl, int block) { diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 22526e98b85b..a75d55577e49 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -43,7 +43,7 @@ static struct vfsmount *mtd_inode_mnt __read_mostly; /* * Data structure to hold the pointer to the mtd device as well - * as mode information ofr various use cases. + * as mode information of various use cases. */ struct mtd_file_info { struct mtd_info *mtd; @@ -495,7 +495,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, /* * Copies (and truncates, if necessary) data from the larger struct, * nand_ecclayout, to the smaller, deprecated layout struct, - * nand_ecclayout_user. This is necessary only to suppport the deprecated + * nand_ecclayout_user. This is necessary only to support the deprecated * API ioctl ECCGETLAYOUT while allowing all new functionality to use * nand_ecclayout flexibly (i.e. the struct may change size in new * releases without requiring major rewrites). diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index e601672a5305..d3fabd144d6c 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -770,7 +770,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c /* * Set up the new "super" device's MTD object structure, check for - * incompatibilites between the subdevices. + * incompatibilities between the subdevices. */ concat->mtd.type = subdev[0]->type; concat->mtd.flags = subdev[0]->flags; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 887aed02aa2e..09bdbac51868 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -449,7 +449,7 @@ int del_mtd_device(struct mtd_info *mtd) * is used, see 'parse_mtd_partitions()' for more information). If none are * found this functions tries to fallback to information specified in * @parts/@nr_parts. - * * If any parititioning info was found, this function registers the found + * * If any partitioning info was found, this function registers the found * partitions. * * If no partitions were found this function just registers the MTD device * @mtd and exits. diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 5e5423b2aed2..9961063b90a2 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -86,7 +86,7 @@ struct swap_eb { unsigned int flags; unsigned int active_count; unsigned int erase_count; - unsigned int pad; /* speeds up pointer decremtnt */ + unsigned int pad; /* speeds up pointer decrement */ }; #define MTDSWAP_ECNT_MIN(rbroot) (rb_entry(rb_first(rbroot), struct swap_eb, \ diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index e3cd1ffad2f6..ac4092591aea 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -32,7 +32,7 @@ /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update - * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] + * the ReplUnitTable[] table according to the Bad Unit Table. ReplUnitTable[] * is used for management of Erase Unit in other routines in nftl.c and nftlmount.c */ static int find_boot_record(struct NFTLrecord *nftl) @@ -297,7 +297,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int * * Return: 0 when succeed, -1 on error. * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it necessary to check_free_sector after erasing ?? */ int NFTL_formatblock(struct NFTLrecord *nftl, int block) { @@ -337,7 +337,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block) nb_erases = le32_to_cpu(uci.WearInfo); nb_erases++; - /* wrap (almost impossible with current flashs) or free block */ + /* wrap (almost impossible with current flash) or free block */ if (nb_erases == 0) nb_erases = 1; @@ -363,10 +363,10 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block) * Mark as 'IGNORE' each incorrect sector. This check is only done if the chain * was being folded when NFTL was interrupted. * - * The check_free_sectors in this function is neceressary. There is a possible + * The check_free_sectors in this function is necessary. There is a possible * situation that after writing the Data area, the Block Control Information is * not updated according (due to power failure or something) which leaves the block - * in an umconsistent state. So we have to check if a block is really FREE in this + * in an inconsistent state. So we have to check if a block is really FREE in this * case. */ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block) { @@ -428,7 +428,7 @@ static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block) for (;;) { length++; - /* avoid infinite loops, although this is guaranted not to + /* avoid infinite loops, although this is guaranteed not to happen because of the previous checks */ if (length >= nftl->nb_blocks) { printk("nftl: length too long %d !\n", length); @@ -447,11 +447,11 @@ static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block) /* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a * Virtual Unit Chain, i.e. all the units are disconnected. * - * It is not stricly correct to begin from the first block of the chain because + * It is not strictly correct to begin from the first block of the chain because * if we stop the code, we may see again a valid chain if there was a first_block * flag in a block inside it. But is it really a problem ? * - * FixMe: Figure out what the last statesment means. What if power failure when we are + * FixMe: Figure out what the last statement means. What if power failure when we are * in the for (;;) loop formatting blocks ?? */ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block) @@ -485,7 +485,7 @@ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block) * totally free (only 0xff). * * Definition: Free Erase Unit -- A properly erased/formatted Free Erase Unit should have meet the - * following critia: + * following criteria: * 1. */ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) { @@ -502,7 +502,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1)); if (erase_mark != ERASE_MARK) { /* if no erase mark, the block must be totally free. This is - possible in two cases : empty filsystem or interrupted erase (very unlikely) */ + possible in two cases : empty filesystem or interrupted erase (very unlikely) */ if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0) return -1; @@ -544,7 +544,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) /* get_fold_mark: Read fold mark from Unit Control Information #2, we use FOLD_MARK_IN_PROGRESS * to indicate that we are in the progression of a Virtual Unit Chain folding. If the UCI #2 * is FOLD_MARK_IN_PROGRESS when mounting the NFTL, the (previous) folding process is interrupted - * for some reason. A clean up/check of the VUC is neceressary in this case. + * for some reason. A clean up/check of the VUC is necessary in this case. * * WARNING: return 0 if read error */ @@ -657,7 +657,7 @@ int NFTL_mount(struct NFTLrecord *s) printk("Block %d: incorrect logical block: %d expected: %d\n", block, logical_block, first_logical_block); /* the chain is incorrect : we must format it, - but we need to read it completly */ + but we need to read it completely */ do_format_chain = 1; } if (is_first_block) { @@ -669,7 +669,7 @@ int NFTL_mount(struct NFTLrecord *s) printk("Block %d: incorrectly marked as first block in chain\n", block); /* the chain is incorrect : we must format it, - but we need to read it completly */ + but we need to read it completely */ do_format_chain = 1; } else { printk("Block %d: folding in progress - ignoring first block flag\n", diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index a8befde81ce9..311a9e39a956 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -34,7 +34,7 @@ module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level (0-2)"); -/* ------------------- sysfs attributtes ---------------------------------- */ +/* ------------------- sysfs attributes ---------------------------------- */ struct sm_sysfs_attribute { struct device_attribute dev_attr; char *data; @@ -147,7 +147,7 @@ static int sm_get_lba(uint8_t *lba) /* - * Read LBA asscociated with block + * Read LBA associated with block * returns -1, if block is erased * returns -2 if error happens */ @@ -252,7 +252,7 @@ static int sm_read_sector(struct sm_ftl *ftl, return 0; } - /* User might not need the oob, but we do for data vertification */ + /* User might not need the oob, but we do for data verification */ if (!oob) oob = &tmp_oob; @@ -276,7 +276,7 @@ static int sm_read_sector(struct sm_ftl *ftl, return ret; } - /* Unfortunelly, oob read will _always_ succeed, + /* Unfortunately, oob read will _always_ succeed, despite card removal..... */ ret = mtd->read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops); @@ -447,14 +447,14 @@ static void sm_mark_block_bad(struct sm_ftl *ftl, int zone, int block) /* We aren't checking the return value, because we don't care */ /* This also fails on fake xD cards, but I guess these won't expose - any bad blocks till fail completly */ + any bad blocks till fail completely */ for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE) sm_write_sector(ftl, zone, block, boffset, NULL, &oob); } /* * Erase a block within a zone - * If erase succedes, it updates free block fifo, otherwise marks block as bad + * If erase succeeds, it updates free block fifo, otherwise marks block as bad */ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block, int put_free) @@ -510,7 +510,7 @@ static void sm_erase_callback(struct erase_info *self) complete(&ftl->erase_completion); } -/* Throughtly test that block is valid. */ +/* Thoroughly test that block is valid. */ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) { int boffset; @@ -526,7 +526,7 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE) { - /* This shoudn't happen anyway */ + /* This shouldn't happen anyway */ if (sm_read_sector(ftl, zone, block, boffset, NULL, &oob)) return -2; From 4aa10626adbc27dcf2e3462bb82b4963c5545669 Mon Sep 17 00:00:00 2001 From: Jonghwan Choi Date: Thu, 21 Jul 2011 15:33:58 +0900 Subject: [PATCH 0316/1596] mtd: s3c2410 nand: Remove uncessary null check clk_get() return a pointer to the struct clk or an ERR_PTR(). Signed-off-by: Jonghwan Choi Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/s3c2410.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b0f8e77834fe..868685db6712 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -723,7 +723,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) /* free the common resources */ - if (info->clk != NULL && !IS_ERR(info->clk)) { + if (!IS_ERR(info->clk)) { s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); clk_put(info->clk); } From f975c6bcb07caacff7fa9904e5d2daa51bcf549d Mon Sep 17 00:00:00 2001 From: Michael Hench Date: Tue, 26 Jul 2011 15:07:42 -0500 Subject: [PATCH 0317/1596] mtd: eLBC NAND: update ecc_stats.corrected when lteccr available Signed-off-by: Michael Hench Acked-by: Scott Wood Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/fsl_elbc_nand.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index acc27ee04749..eedd8ee2c9ac 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -243,6 +243,25 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) return -EIO; } + if (chip->ecc.mode != NAND_ECC_HW) + return 0; + + if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) { + uint32_t lteccr = in_be32(&lbc->lteccr); + /* + * if command was a full page read and the ELBC + * has the LTECCR register, then bits 12-15 (ppc order) of + * LTECCR indicates which 512 byte sub-pages had fixed errors. + * bits 28-31 are uncorrectable errors, marked elsewhere. + * for small page nand only 1 bit is used. + * if the ELBC doesn't have the lteccr register it reads 0 + */ + if (lteccr & 0x000F000F) + out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ + if (lteccr & 0x000F0000) + mtd->ecc_stats.corrected++; + } + return 0; } From 38ca6ebc72d59c0c4f52d443c69fc4a17765666a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 10 Aug 2011 10:14:14 +0200 Subject: [PATCH 0318/1596] mtd: bcm_umi_nand: clean up error handling code Convert error handling code to use gotos. At the same time, this adds calls to kfree and iounmap in a few cases where they were overlooked. Signed-off-by: Julia Lawall Acked-by: Jiandong Zheng Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/bcm_umi_nand.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index a8ae89865a86..46b58d672847 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -374,16 +374,18 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENXIO; + if (!r) { + err = -ENXIO; + goto out_free; + } /* map physical address */ bcm_umi_io_base = ioremap(r->start, resource_size(r)); if (!bcm_umi_io_base) { printk(KERN_ERR "ioremap to access BCM UMI NAND chip failed\n"); - kfree(board_mtd); - return -EIO; + err = -EIO; + goto out_free; } /* Get pointer to private data */ @@ -399,9 +401,8 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) /* Initialize the NAND hardware. */ if (bcm_umi_nand_inithw() < 0) { printk(KERN_ERR "BCM UMI NAND chip could not be initialized\n"); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return -EIO; + err = -EIO; + goto out_unmap; } /* Set address of NAND IO lines */ @@ -434,7 +435,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) #if USE_DMA err = nand_dma_init(); if (err != 0) - return err; + goto out_unmap; #endif /* Figure out the size of the device that we have. @@ -445,9 +446,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) err = nand_scan_ident(board_mtd, 1, NULL); if (err) { printk(KERN_ERR "nand_scan failed: %d\n", err); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return err; + goto out_unmap; } /* Now that we know the nand size, we can setup the ECC layout */ @@ -466,7 +465,8 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) { printk(KERN_ERR "NAND - Unrecognized pagesize: %d\n", board_mtd->writesize); - return -EINVAL; + err = -EINVAL; + goto out_unmap; } } @@ -483,9 +483,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) err = nand_scan_tail(board_mtd); if (err) { printk(KERN_ERR "nand_scan failed: %d\n", err); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return err; + goto out_unmap; } /* Register the partitions */ @@ -494,6 +492,11 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) /* Return happy */ return 0; +out_unmap: + iounmap(bcm_umi_io_base); +out_free: + kfree(board_mtd); + return err; } static int bcm_umi_nand_remove(struct platform_device *pdev) From c97926dd8d7cc094830b253afc817cbf406c0de7 Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Mon, 22 Aug 2011 14:13:17 +0800 Subject: [PATCH 0319/1596] mtd: mxc_nand: add mx53 NFC driver support This has already been tested with Samsung NAND: K9LAG08U0M on MX53EVK board, ubi/ubifs has already been tested OK too. Signed-off-by: Jason Liu Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/mxc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ebeb84316ecd..4d4c67763cb0 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -41,7 +41,7 @@ #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) -#define nfc_is_v3_2() cpu_is_mx51() +#define nfc_is_v3_2() (cpu_is_mx51() || cpu_is_mx53()) #define nfc_is_v3() nfc_is_v3_2() /* Addresses for NFC registers */ From 305b93f180b221789a6213bf3d298c6735102da1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 23 Aug 2011 17:17:32 -0700 Subject: [PATCH 0320/1596] mtd: do not assume oobsize is power of 2 Previous generations of MTDs all used OOB sizes that were powers of 2, (e.g., 64, 128). However, newer generations of flash, especially NAND, use irregular OOB sizes that are not powers of 2 (e.g., 218, 224, 448). This means we cannot use masks like "mtd->oobsize - 1" to assume that we will get a proper bitmask for OOB operations. These masks are really only intended to hide the "page" portion of the offset, leaving any OOB offset intact, so a masking with the writesize (which *is* always a power of 2) is valid and makes more sense. This has been tested for read/write of NAND devices (nanddump/nandwrite) using nandsim and actual NAND flash. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index a75d55577e49..b20625475132 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -410,7 +410,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, return ret; ops.ooblen = length; - ops.ooboffs = start & (mtd->oobsize - 1); + ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; ops.mode = MTD_OOB_PLACE; @@ -421,7 +421,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, if (IS_ERR(ops.oobbuf)) return PTR_ERR(ops.oobbuf); - start &= ~((uint64_t)mtd->oobsize - 1); + start &= ~((uint64_t)mtd->writesize - 1); ret = mtd->write_oob(mtd, start, &ops); if (ops.oobretlen > 0xFFFFFFFFU) @@ -452,7 +452,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, return ret; ops.ooblen = length; - ops.ooboffs = start & (mtd->oobsize - 1); + ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; ops.mode = MTD_OOB_PLACE; @@ -463,7 +463,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, if (!ops.oobbuf) return -ENOMEM; - start &= ~((uint64_t)mtd->oobsize - 1); + start &= ~((uint64_t)mtd->writesize - 1); ret = mtd->read_oob(mtd, start, &ops); if (put_user(ops.oobretlen, retp)) From 48ee688df09fa3ddf86b5b53508316d18d6fcedd Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 23 Aug 2011 17:17:33 -0700 Subject: [PATCH 0321/1596] mtd: doc: remove mention of MEMSETOOBSEL It's been gone for a while. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- Documentation/DocBook/mtdnand.tmpl | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index 8c07540c181c..0c674be0d3c6 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -773,20 +773,6 @@ struct nand_oobinfo { done according to the default builtin scheme. - - User space placement selection - - All non ecc functions like mtd->read and mtd->write use an internal - structure, which can be set by an ioctl. This structure is preset - to the autoplacement default. - - ioctl (fd, MEMSETOOBSEL, oobsel); - - oobsel is a pointer to a user supplied structure of type - nand_oobconfig. The contents of this structure must match the - criteria of the filesystem, which will be used. See an example in utils/nandwrite.c. - - Spare area autoplacement default schemes From 93fad71c206ca4672360edaf918727b2b64f8ad1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 23 Aug 2011 17:17:34 -0700 Subject: [PATCH 0322/1596] mtd: remove MEMSETOOBSEL macro definition MEMSETOOBSEL is completely unused and useless. Remove the definition. Note: it's probably best not to use this ioctl number in the future for MTD, since that may cause conflicts between old kernels and new user software (or new kernels and old user software). Artem: leave a comment about MEMSETOOBSEL. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/mtd/mtd-abi.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 2f7d45bcbd24..3bdda5c426bd 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -104,6 +104,12 @@ struct otp_info { __u32 locked; }; +/* + * Note, the following ioctl existed in the past and was removed: + * #define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) + * Try to avoid adding a new ioctl with the same ioctl number. + */ + #define MEMGETINFO _IOR('M', 1, struct mtd_info_user) #define MEMERASE _IOW('M', 2, struct erase_info_user) #define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) @@ -112,7 +118,6 @@ struct otp_info { #define MEMUNLOCK _IOW('M', 6, struct erase_info_user) #define MEMGETREGIONCOUNT _IOR('M', 7, int) #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) -#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) #define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) #define MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t) #define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t) From 32c8db8f622a4cb8ea9d571d462580f7137babbb Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 23 Aug 2011 17:17:35 -0700 Subject: [PATCH 0323/1596] mtd: nand: fix spelling error (date => data) Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/linux/mtd/nand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 6d5696876b3f..85fef68a379d 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -465,7 +465,7 @@ struct nand_buffers { * @controller: [REPLACEABLE] a pointer to a hardware controller * structure which is shared among multiple independent * devices. - * @priv: [OPTIONAL] pointer to private chip date + * @priv: [OPTIONAL] pointer to private chip data * @errstat: [OPTIONAL] hardware specific function to perform * additional error status checks (determine if errors are * correctable). From e2e24e8ebf0e96571fbbac95c215df6a2cebbc5b Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 23 Aug 2011 17:17:36 -0700 Subject: [PATCH 0324/1596] mtd: style fixups in multi-line comment, indentation Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/linux/mtd/mtd.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 68ea22963a33..ff7bae08c5e0 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -33,17 +33,19 @@ #define MTD_CHAR_MAJOR 90 #define MTD_BLOCK_MAJOR 31 -#define MTD_ERASE_PENDING 0x01 +#define MTD_ERASE_PENDING 0x01 #define MTD_ERASING 0x02 #define MTD_ERASE_SUSPEND 0x04 -#define MTD_ERASE_DONE 0x08 -#define MTD_ERASE_FAILED 0x10 +#define MTD_ERASE_DONE 0x08 +#define MTD_ERASE_FAILED 0x10 #define MTD_FAIL_ADDR_UNKNOWN -1LL -/* If the erase fails, fail_addr might indicate exactly which block failed. If - fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level or was not - specific to any particular block. */ +/* + * If the erase fails, fail_addr might indicate exactly which block failed. If + * fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level + * or was not specific to any particular block. + */ struct erase_info { struct mtd_info *mtd; uint64_t addr; @@ -60,7 +62,7 @@ struct erase_info { }; struct mtd_erase_region_info { - uint64_t offset; /* At which this region starts, from the beginning of the MTD */ + uint64_t offset; /* At which this region starts, from the beginning of the MTD */ uint32_t erasesize; /* For this region */ uint32_t numblocks; /* Number of blocks of erasesize in this region */ unsigned long *lockmap; /* If keeping bitmap of locks */ From 4d523b60ef9d1953d9e12745ca0ed3e2dc98c189 Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Wed, 24 Aug 2011 19:26:28 +0800 Subject: [PATCH 0325/1596] mtd: check parts pointer before using it The code has the check for parts but it called after kmemdup, kmemdup(parts, sizeof(*parts) * nr_parts,...) if (!parts) return -ENOMEM In fact, we need check parts before safely using it. and we also need check the real_parts to make sure kmemdup allocation sucessfully. Signed-off-by: Jason Liu Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdcore.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 09bdbac51868..b01993ea260e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -465,12 +465,13 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char **types, struct mtd_partition *real_parts; err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); - if (err <= 0 && nr_parts) { + if (err <= 0 && nr_parts && parts) { real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, GFP_KERNEL); - err = nr_parts; - if (!parts) + if (!real_parts) err = -ENOMEM; + else + err = nr_parts; } if (err > 0) { From 45dfc1a09a35963234a50617c0700f7eb2b3b9c2 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 8 Sep 2011 10:47:10 +0800 Subject: [PATCH 0326/1596] mtd: add helper functions library and header files for GPMI NAND driver bch-regs.h : registers file for BCH module gpmi-regs.h: registers file for GPMI module gpmi-lib.c: helper functions library. Signed-off-by: Huang Shijie Acked-by: Marek Vasut Tested-by: Koen Beel Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/gpmi-nand/bch-regs.h | 84 ++ drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 1057 ++++++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-regs.h | 172 ++++ 3 files changed, 1313 insertions(+) create mode 100644 drivers/mtd/nand/gpmi-nand/bch-regs.h create mode 100644 drivers/mtd/nand/gpmi-nand/gpmi-lib.c create mode 100644 drivers/mtd/nand/gpmi-nand/gpmi-regs.h diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h new file mode 100644 index 000000000000..4effb8c579db --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/bch-regs.h @@ -0,0 +1,84 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __GPMI_NAND_BCH_REGS_H +#define __GPMI_NAND_BCH_REGS_H + +#define HW_BCH_CTRL 0x00000000 +#define HW_BCH_CTRL_SET 0x00000004 +#define HW_BCH_CTRL_CLR 0x00000008 +#define HW_BCH_CTRL_TOG 0x0000000c + +#define BM_BCH_CTRL_COMPLETE_IRQ_EN (1 << 8) +#define BM_BCH_CTRL_COMPLETE_IRQ (1 << 0) + +#define HW_BCH_STATUS0 0x00000010 +#define HW_BCH_MODE 0x00000020 +#define HW_BCH_ENCODEPTR 0x00000030 +#define HW_BCH_DATAPTR 0x00000040 +#define HW_BCH_METAPTR 0x00000050 +#define HW_BCH_LAYOUTSELECT 0x00000070 + +#define HW_BCH_FLASH0LAYOUT0 0x00000080 + +#define BP_BCH_FLASH0LAYOUT0_NBLOCKS 24 +#define BM_BCH_FLASH0LAYOUT0_NBLOCKS (0xff << BP_BCH_FLASH0LAYOUT0_NBLOCKS) +#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_NBLOCKS) & BM_BCH_FLASH0LAYOUT0_NBLOCKS) + +#define BP_BCH_FLASH0LAYOUT0_META_SIZE 16 +#define BM_BCH_FLASH0LAYOUT0_META_SIZE (0xff << BP_BCH_FLASH0LAYOUT0_META_SIZE) +#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_META_SIZE)\ + & BM_BCH_FLASH0LAYOUT0_META_SIZE) + +#define BP_BCH_FLASH0LAYOUT0_ECC0 12 +#define BM_BCH_FLASH0LAYOUT0_ECC0 (0xf << BP_BCH_FLASH0LAYOUT0_ECC0) +#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) & BM_BCH_FLASH0LAYOUT0_ECC0) + +#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0 +#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \ + (0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) +#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)\ + & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) + +#define HW_BCH_FLASH0LAYOUT1 0x00000090 + +#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16 +#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE \ + (0xffff << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) +#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) \ + & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE) + +#define BP_BCH_FLASH0LAYOUT1_ECCN 12 +#define BM_BCH_FLASH0LAYOUT1_ECCN (0xf << BP_BCH_FLASH0LAYOUT1_ECCN) +#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) & BM_BCH_FLASH0LAYOUT1_ECCN) + +#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0 +#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \ + (0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) +#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ + & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) +#endif diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c new file mode 100644 index 000000000000..de4db7604a3f --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -0,0 +1,1057 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include +#include +#include +#include + +#include "gpmi-nand.h" +#include "gpmi-regs.h" +#include "bch-regs.h" + +struct timing_threshod timing_default_threshold = { + .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >> + BP_GPMI_TIMING0_DATA_SETUP), + .internal_data_setup_in_ns = 0, + .max_sample_delay_factor = (BM_GPMI_CTRL1_RDN_DELAY >> + BP_GPMI_CTRL1_RDN_DELAY), + .max_dll_clock_period_in_ns = 32, + .max_dll_delay_in_ns = 16, +}; + +/* + * Clear the bit and poll it cleared. This is usually called with + * a reset address and mask being either SFTRST(bit 31) or CLKGATE + * (bit 30). + */ +static int clear_poll_bit(void __iomem *addr, u32 mask) +{ + int timeout = 0x400; + + /* clear the bit */ + __mxs_clrl(mask, addr); + + /* + * SFTRST needs 3 GPMI clocks to settle, the reference manual + * recommends to wait 1us. + */ + udelay(1); + + /* poll the bit becoming clear */ + while ((readl(addr) & mask) && --timeout) + /* nothing */; + + return !timeout; +} + +#define MODULE_CLKGATE (1 << 30) +#define MODULE_SFTRST (1 << 31) +/* + * The current mxs_reset_block() will do two things: + * [1] enable the module. + * [2] reset the module. + * + * In most of the cases, it's ok. But there is a hardware bug in the BCH block. + * If you try to soft reset the BCH block, it becomes unusable until + * the next hard reset. This case occurs in the NAND boot mode. When the board + * boots by NAND, the ROM of the chip will initialize the BCH blocks itself. + * So If the driver tries to reset the BCH again, the BCH will not work anymore. + * You will see a DMA timeout in this case. + * + * To avoid this bug, just add a new parameter `just_enable` for + * the mxs_reset_block(), and rewrite it here. + */ +int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) +{ + int ret; + int timeout = 0x400; + + /* clear and poll SFTRST */ + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); + if (unlikely(ret)) + goto error; + + /* clear CLKGATE */ + __mxs_clrl(MODULE_CLKGATE, reset_addr); + + if (!just_enable) { + /* set SFTRST to reset the block */ + __mxs_setl(MODULE_SFTRST, reset_addr); + udelay(1); + + /* poll CLKGATE becoming set */ + while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout) + /* nothing */; + if (unlikely(!timeout)) + goto error; + } + + /* clear and poll SFTRST */ + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); + if (unlikely(ret)) + goto error; + + /* clear and poll CLKGATE */ + ret = clear_poll_bit(reset_addr, MODULE_CLKGATE); + if (unlikely(ret)) + goto error; + + return 0; + +error: + pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); + return -ETIMEDOUT; +} + +int gpmi_init(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + int ret; + + ret = clk_enable(r->clock); + if (ret) + goto err_out; + ret = gpmi_reset_block(r->gpmi_regs, false); + if (ret) + goto err_out; + + /* Choose NAND mode. */ + writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* Set the IRQ polarity. */ + writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY, + r->gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Disable Write-Protection. */ + writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Select BCH ECC. */ + writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); + + clk_disable(r->clock); + return 0; +err_out: + return ret; +} + +/* This function is very useful. It is called only when the bug occur. */ +void gpmi_dump_info(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct bch_geometry *geo = &this->bch_geometry; + u32 reg; + int i; + + pr_err("Show GPMI registers :\n"); + for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) { + reg = readl(r->gpmi_regs + i * 0x10); + pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + } + + /* start to print out the BCH info */ + pr_err("BCH Geometry :\n"); + pr_err("GF length : %u\n", geo->gf_len); + pr_err("ECC Strength : %u\n", geo->ecc_strength); + pr_err("Page Size in Bytes : %u\n", geo->page_size); + pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size); + pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size); + pr_err("ECC Chunk Count : %u\n", geo->ecc_chunk_count); + pr_err("Payload Size in Bytes : %u\n", geo->payload_size); + pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size); + pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset); + pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset); + pr_err("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset); +} + +/* Configures the geometry for BCH. */ +int bch_set_geometry(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct bch_geometry *bch_geo = &this->bch_geometry; + unsigned int block_count; + unsigned int block_size; + unsigned int metadata_size; + unsigned int ecc_strength; + unsigned int page_size; + int ret; + + if (common_nfc_set_geometry(this)) + return !0; + + block_count = bch_geo->ecc_chunk_count - 1; + block_size = bch_geo->ecc_chunk_size; + metadata_size = bch_geo->metadata_size; + ecc_strength = bch_geo->ecc_strength >> 1; + page_size = bch_geo->page_size; + + ret = clk_enable(r->clock); + if (ret) + goto err_out; + + ret = gpmi_reset_block(r->bch_regs, true); + if (ret) + goto err_out; + + /* Configure layout 0. */ + writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) + | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) + | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) + | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size), + r->bch_regs + HW_BCH_FLASH0LAYOUT0); + + writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) + | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) + | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size), + r->bch_regs + HW_BCH_FLASH0LAYOUT1); + + /* Set *all* chip selects to use layout 0. */ + writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT); + + /* Enable interrupts. */ + writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, + r->bch_regs + HW_BCH_CTRL_SET); + + clk_disable(r->clock); + return 0; +err_out: + return ret; +} + +/* Converts time in nanoseconds to cycles. */ +static unsigned int ns_to_cycles(unsigned int time, + unsigned int period, unsigned int min) +{ + unsigned int k; + + k = (time + period - 1) / period; + return max(k, min); +} + +/* Apply timing to current hardware conditions. */ +static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, + struct gpmi_nfc_hardware_timing *hw) +{ + struct gpmi_nand_platform_data *pdata = this->pdata; + struct timing_threshod *nfc = &timing_default_threshold; + struct nand_chip *nand = &this->nand; + struct nand_timing target = this->timing; + bool improved_timing_is_available; + unsigned long clock_frequency_in_hz; + unsigned int clock_period_in_ns; + bool dll_use_half_periods; + unsigned int dll_delay_shift; + unsigned int max_sample_delay_in_ns; + unsigned int address_setup_in_cycles; + unsigned int data_setup_in_ns; + unsigned int data_setup_in_cycles; + unsigned int data_hold_in_cycles; + int ideal_sample_delay_in_ns; + unsigned int sample_delay_factor; + int tEYE; + unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns; + unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns; + + /* + * If there are multiple chips, we need to relax the timings to allow + * for signal distortion due to higher capacitance. + */ + if (nand->numchips > 2) { + target.data_setup_in_ns += 10; + target.data_hold_in_ns += 10; + target.address_setup_in_ns += 10; + } else if (nand->numchips > 1) { + target.data_setup_in_ns += 5; + target.data_hold_in_ns += 5; + target.address_setup_in_ns += 5; + } + + /* Check if improved timing information is available. */ + improved_timing_is_available = + (target.tREA_in_ns >= 0) && + (target.tRLOH_in_ns >= 0) && + (target.tRHOH_in_ns >= 0) ; + + /* Inspect the clock. */ + clock_frequency_in_hz = nfc->clock_frequency_in_hz; + clock_period_in_ns = 1000000000 / clock_frequency_in_hz; + + /* + * The NFC quantizes setup and hold parameters in terms of clock cycles. + * Here, we quantize the setup and hold timing parameters to the + * next-highest clock period to make sure we apply at least the + * specified times. + * + * For data setup and data hold, the hardware interprets a value of zero + * as the largest possible delay. This is not what's intended by a zero + * in the input parameter, so we impose a minimum of one cycle. + */ + data_setup_in_cycles = ns_to_cycles(target.data_setup_in_ns, + clock_period_in_ns, 1); + data_hold_in_cycles = ns_to_cycles(target.data_hold_in_ns, + clock_period_in_ns, 1); + address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns, + clock_period_in_ns, 0); + + /* + * The clock's period affects the sample delay in a number of ways: + * + * (1) The NFC HAL tells us the maximum clock period the sample delay + * DLL can tolerate. If the clock period is greater than half that + * maximum, we must configure the DLL to be driven by half periods. + * + * (2) We need to convert from an ideal sample delay, in ns, to a + * "sample delay factor," which the NFC uses. This factor depends on + * whether we're driving the DLL with full or half periods. + * Paraphrasing the reference manual: + * + * AD = SDF x 0.125 x RP + * + * where: + * + * AD is the applied delay, in ns. + * SDF is the sample delay factor, which is dimensionless. + * RP is the reference period, in ns, which is a full clock period + * if the DLL is being driven by full periods, or half that if + * the DLL is being driven by half periods. + * + * Let's re-arrange this in a way that's more useful to us: + * + * 8 + * SDF = AD x ---- + * RP + * + * The reference period is either the clock period or half that, so this + * is: + * + * 8 AD x DDF + * SDF = AD x ----- = -------- + * f x P P + * + * where: + * + * f is 1 or 1/2, depending on how we're driving the DLL. + * P is the clock period. + * DDF is the DLL Delay Factor, a dimensionless value that + * incorporates all the constants in the conversion. + * + * DDF will be either 8 or 16, both of which are powers of two. We can + * reduce the cost of this conversion by using bit shifts instead of + * multiplication or division. Thus: + * + * AD << DDS + * SDF = --------- + * P + * + * or + * + * AD = (SDF >> DDS) x P + * + * where: + * + * DDS is the DLL Delay Shift, the logarithm to base 2 of the DDF. + */ + if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) { + dll_use_half_periods = true; + dll_delay_shift = 3 + 1; + } else { + dll_use_half_periods = false; + dll_delay_shift = 3; + } + + /* + * Compute the maximum sample delay the NFC allows, under current + * conditions. If the clock is running too slowly, no sample delay is + * possible. + */ + if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns) + max_sample_delay_in_ns = 0; + else { + /* + * Compute the delay implied by the largest sample delay factor + * the NFC allows. + */ + max_sample_delay_in_ns = + (nfc->max_sample_delay_factor * clock_period_in_ns) >> + dll_delay_shift; + + /* + * Check if the implied sample delay larger than the NFC + * actually allows. + */ + if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns) + max_sample_delay_in_ns = nfc->max_dll_delay_in_ns; + } + + /* + * Check if improved timing information is available. If not, we have to + * use a less-sophisticated algorithm. + */ + if (!improved_timing_is_available) { + /* + * Fold the read setup time required by the NFC into the ideal + * sample delay. + */ + ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns + + nfc->internal_data_setup_in_ns; + + /* + * The ideal sample delay may be greater than the maximum + * allowed by the NFC. If so, we can trade off sample delay time + * for more data setup time. + * + * In each iteration of the following loop, we add a cycle to + * the data setup time and subtract a corresponding amount from + * the sample delay until we've satisified the constraints or + * can't do any better. + */ + while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + + data_setup_in_cycles++; + ideal_sample_delay_in_ns -= clock_period_in_ns; + + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + } + + /* + * Compute the sample delay factor that corresponds most closely + * to the ideal sample delay. If the result is too large for the + * NFC, use the maximum value. + * + * Notice that we use the ns_to_cycles function to compute the + * sample delay factor. We do this because the form of the + * computation is the same as that for calculating cycles. + */ + sample_delay_factor = + ns_to_cycles( + ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + + /* Skip to the part where we return our results. */ + goto return_results; + } + + /* + * If control arrives here, we have more detailed timing information, + * so we can use a better algorithm. + */ + + /* + * Fold the read setup time required by the NFC into the maximum + * propagation delay. + */ + max_prop_delay_in_ns += nfc->internal_data_setup_in_ns; + + /* + * Earlier, we computed the number of clock cycles required to satisfy + * the data setup time. Now, we need to know the actual nanoseconds. + */ + data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles; + + /* + * Compute tEYE, the width of the data eye when reading from the NAND + * Flash. The eye width is fundamentally determined by the data setup + * time, perturbed by propagation delays and some characteristics of the + * NAND Flash device. + * + * start of the eye = max_prop_delay + tREA + * end of the eye = min_prop_delay + tRHOH + data_setup + */ + tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns + + (int)data_setup_in_ns; + + tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns; + + /* + * The eye must be open. If it's not, we can try to open it by + * increasing its main forcer, the data setup time. + * + * In each iteration of the following loop, we increase the data setup + * time by a single clock cycle. We do this until either the eye is + * open or we run into NFC limits. + */ + while ((tEYE <= 0) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + } + + /* + * When control arrives here, the eye is open. The ideal time to sample + * the data is in the center of the eye: + * + * end of the eye + start of the eye + * --------------------------------- - data_setup + * 2 + * + * After some algebra, this simplifies to the code immediately below. + */ + ideal_sample_delay_in_ns = + ((int)max_prop_delay_in_ns + + (int)target.tREA_in_ns + + (int)min_prop_delay_in_ns + + (int)target.tRHOH_in_ns - + (int)data_setup_in_ns) >> 1; + + /* + * The following figure illustrates some aspects of a NAND Flash read: + * + * + * __ _____________________________________ + * RDN \_________________/ + * + * <---- tEYE -----> + * /-----------------\ + * Read Data ----------------------------< >--------- + * \-----------------/ + * ^ ^ ^ ^ + * | | | | + * |<--Data Setup -->|<--Delay Time -->| | + * | | | | + * | | | + * | |<-- Quantized Delay Time -->| + * | | | + * + * + * We have some issues we must now address: + * + * (1) The *ideal* sample delay time must not be negative. If it is, we + * jam it to zero. + * + * (2) The *ideal* sample delay time must not be greater than that + * allowed by the NFC. If it is, we can increase the data setup + * time, which will reduce the delay between the end of the data + * setup and the center of the eye. It will also make the eye + * larger, which might help with the next issue... + * + * (3) The *quantized* sample delay time must not fall either before the + * eye opens or after it closes (the latter is the problem + * illustrated in the above figure). + */ + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + /* + * Extend the data setup as needed to reduce the ideal sample delay + * below the maximum permitted by the NFC. + */ + while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + + /* + * Decrease the ideal sample delay by one half cycle, to keep it + * in the middle of the eye. + */ + ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + } + + /* + * Compute the sample delay factor that corresponds to the ideal sample + * delay. If the result is too large, then use the maximum allowed + * value. + * + * Notice that we use the ns_to_cycles function to compute the sample + * delay factor. We do this because the form of the computation is the + * same as that for calculating cycles. + */ + sample_delay_factor = + ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + + /* + * These macros conveniently encapsulate a computation we'll use to + * continuously evaluate whether or not the data sample delay is inside + * the eye. + */ + #define IDEAL_DELAY ((int) ideal_sample_delay_in_ns) + + #define QUANTIZED_DELAY \ + ((int) ((sample_delay_factor * clock_period_in_ns) >> \ + dll_delay_shift)) + + #define DELAY_ERROR (abs(QUANTIZED_DELAY - IDEAL_DELAY)) + + #define SAMPLE_IS_NOT_WITHIN_THE_EYE (DELAY_ERROR > (tEYE >> 1)) + + /* + * While the quantized sample time falls outside the eye, reduce the + * sample delay or extend the data setup to move the sampling point back + * toward the eye. Do not allow the number of data setup cycles to + * exceed the maximum allowed by the NFC. + */ + while (SAMPLE_IS_NOT_WITHIN_THE_EYE && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + /* + * If control arrives here, the quantized sample delay falls + * outside the eye. Check if it's before the eye opens, or after + * the eye closes. + */ + if (QUANTIZED_DELAY > IDEAL_DELAY) { + /* + * If control arrives here, the quantized sample delay + * falls after the eye closes. Decrease the quantized + * delay time and then go back to re-evaluate. + */ + if (sample_delay_factor != 0) + sample_delay_factor--; + continue; + } + + /* + * If control arrives here, the quantized sample delay falls + * before the eye opens. Shift the sample point by increasing + * data setup time. This will also make the eye larger. + */ + + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + + /* + * Decrease the ideal sample delay by one half cycle, to keep it + * in the middle of the eye. + */ + ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); + + /* ...and one less period for the delay time. */ + ideal_sample_delay_in_ns -= clock_period_in_ns; + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + /* + * We have a new ideal sample delay, so re-compute the quantized + * delay. + */ + sample_delay_factor = + ns_to_cycles( + ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + } + + /* Control arrives here when we're ready to return our results. */ +return_results: + hw->data_setup_in_cycles = data_setup_in_cycles; + hw->data_hold_in_cycles = data_hold_in_cycles; + hw->address_setup_in_cycles = address_setup_in_cycles; + hw->use_half_periods = dll_use_half_periods; + hw->sample_delay_factor = sample_delay_factor; + + /* Return success. */ + return 0; +} + +/* Begin the I/O */ +void gpmi_begin(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct timing_threshod *nfc = &timing_default_threshold; + unsigned char *gpmi_regs = r->gpmi_regs; + unsigned int clock_period_in_ns; + uint32_t reg; + unsigned int dll_wait_time_in_us; + struct gpmi_nfc_hardware_timing hw; + int ret; + + /* Enable the clock. */ + ret = clk_enable(r->clock); + if (ret) { + pr_err("We failed in enable the clk\n"); + goto err_out; + } + + /* set ready/busy timeout */ + writel(0x500 << BP_GPMI_TIMING1_BUSY_TIMEOUT, + gpmi_regs + HW_GPMI_TIMING1); + + /* Get the timing information we need. */ + nfc->clock_frequency_in_hz = clk_get_rate(r->clock); + clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz; + + gpmi_nfc_compute_hardware_timing(this, &hw); + + /* Set up all the simple timing parameters. */ + reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | + BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles) | + BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles) ; + + writel(reg, gpmi_regs + HW_GPMI_TIMING0); + + /* + * DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. + */ + writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* Clear out the DLL control fields. */ + writel(BM_GPMI_CTRL1_RDN_DELAY, gpmi_regs + HW_GPMI_CTRL1_CLR); + writel(BM_GPMI_CTRL1_HALF_PERIOD, gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* If no sample delay is called for, return immediately. */ + if (!hw.sample_delay_factor) + return; + + /* Configure the HALF_PERIOD flag. */ + if (hw.use_half_periods) + writel(BM_GPMI_CTRL1_HALF_PERIOD, + gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Set the delay factor. */ + writel(BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor), + gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Enable the DLL. */ + writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET); + + /* + * After we enable the GPMI DLL, we have to wait 64 clock cycles before + * we can use the GPMI. + * + * Calculate the amount of time we need to wait, in microseconds. + */ + dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000; + + if (!dll_wait_time_in_us) + dll_wait_time_in_us = 1; + + /* Wait for the DLL to settle. */ + udelay(dll_wait_time_in_us); + +err_out: + return; +} + +void gpmi_end(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + clk_disable(r->clock); +} + +/* Clears a BCH interrupt. */ +void gpmi_clear_bch(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR); +} + +/* Returns the Ready/Busy status of the given chip. */ +int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) +{ + struct resources *r = &this->resources; + uint32_t mask = 0; + uint32_t reg = 0; + + if (GPMI_IS_MX23(this)) { + mask = MX23_BM_GPMI_DEBUG_READY0 << chip; + reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); + } else if (GPMI_IS_MX28(this)) { + mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); + reg = readl(r->gpmi_regs + HW_GPMI_STAT); + } else + pr_err("unknow arch.\n"); + return reg & mask; +} + +static inline void set_dma_type(struct gpmi_nand_data *this, + enum dma_ops_type type) +{ + this->last_dma_type = this->dma_type; + this->dma_type = type; +} + +int gpmi_send_command(struct gpmi_nand_data *this) +{ + struct dma_chan *channel = get_dma_chan(this); + struct dma_async_tx_descriptor *desc; + struct scatterlist *sgl; + int chip = this->current_chip; + u32 pio[3]; + + /* [1] send out the PIO words */ + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) + | BM_GPMI_CTRL0_ADDRESS_INCREMENT + | BF_GPMI_CTRL0_XFER_COUNT(this->command_length); + pio[1] = pio[2] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] send out the COMMAND + ADDRESS string stored in @buffer */ + sgl = &this->cmd_sgl; + + sg_init_one(sgl, this->cmd_buffer, this->command_length); + dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, + sgl, 1, DMA_TO_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] submit the DMA */ + set_dma_type(this, DMA_FOR_COMMAND); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_send_data(struct gpmi_nand_data *this) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + uint32_t command_mode; + uint32_t address; + u32 pio[2]; + + /* [1] PIO */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(this->upper_len); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] send DMA request */ + prepare_data_dma(this, DMA_TO_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, + 1, DMA_TO_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + /* [3] submit the DMA */ + set_dma_type(this, DMA_FOR_WRITE_DATA); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_read_data(struct gpmi_nand_data *this) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[2]; + + /* [1] : send PIO */ + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) + | BF_GPMI_CTRL0_XFER_COUNT(this->upper_len); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] : send DMA request */ + prepare_data_dma(this, DMA_FROM_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, + 1, DMA_FROM_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] : submit the DMA */ + set_dma_type(this, DMA_FOR_READ_DATA); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_send_page(struct gpmi_nand_data *this, + dma_addr_t payload, dma_addr_t auxiliary) +{ + struct bch_geometry *geo = &this->bch_geometry; + uint32_t command_mode; + uint32_t address; + uint32_t ecc_command; + uint32_t buffer_mask; + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[6]; + + /* A DMA descriptor that does an ECC page read. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE; + buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE | + BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(0); + pio[1] = 0; + pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC + | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) + | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); + pio[3] = geo->page_size; + pio[4] = payload; + pio[5] = auxiliary; + + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE); + return start_dma_with_bch_irq(this, desc); +} + +int gpmi_read_page(struct gpmi_nand_data *this, + dma_addr_t payload, dma_addr_t auxiliary) +{ + struct bch_geometry *geo = &this->bch_geometry; + uint32_t command_mode; + uint32_t address; + uint32_t ecc_command; + uint32_t buffer_mask; + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[6]; + + /* [1] Wait for the chip to report ready. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(0); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, 2, DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] Enable the BCH block and read. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE; + buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE + | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); + + pio[1] = 0; + pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC + | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) + | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); + pio[3] = geo->page_size; + pio[4] = payload; + pio[5] = auxiliary; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] Disable the BCH block */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, 2, DMA_NONE, 1); + if (!desc) { + pr_err("step 3 error\n"); + return -1; + } + + /* [4] submit the DMA */ + set_dma_type(this, DMA_FOR_READ_ECC_PAGE); + return start_dma_with_bch_irq(this, desc); +} diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h new file mode 100644 index 000000000000..83431240e2f2 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h @@ -0,0 +1,172 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __GPMI_NAND_GPMI_REGS_H +#define __GPMI_NAND_GPMI_REGS_H + +#define HW_GPMI_CTRL0 0x00000000 +#define HW_GPMI_CTRL0_SET 0x00000004 +#define HW_GPMI_CTRL0_CLR 0x00000008 +#define HW_GPMI_CTRL0_TOG 0x0000000c + +#define BP_GPMI_CTRL0_COMMAND_MODE 24 +#define BM_GPMI_CTRL0_COMMAND_MODE (3 << BP_GPMI_CTRL0_COMMAND_MODE) +#define BF_GPMI_CTRL0_COMMAND_MODE(v) \ + (((v) << BP_GPMI_CTRL0_COMMAND_MODE) & BM_GPMI_CTRL0_COMMAND_MODE) +#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2 +#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3 + +#define BM_GPMI_CTRL0_WORD_LENGTH (1 << 23) +#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT 0x0 +#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT 0x1 + +/* + * Difference in LOCK_CS between imx23 and imx28 : + * This bit may impact the _POWER_ consumption. So some chips + * do not set it. + */ +#define MX23_BP_GPMI_CTRL0_LOCK_CS 22 +#define MX28_BP_GPMI_CTRL0_LOCK_CS 27 +#define LOCK_CS_ENABLE 0x1 +#define BF_GPMI_CTRL0_LOCK_CS(v, x) 0x0 + +/* Difference in CS between imx23 and imx28 */ +#define BP_GPMI_CTRL0_CS 20 +#define MX23_BM_GPMI_CTRL0_CS (3 << BP_GPMI_CTRL0_CS) +#define MX28_BM_GPMI_CTRL0_CS (7 << BP_GPMI_CTRL0_CS) +#define BF_GPMI_CTRL0_CS(v, x) (((v) << BP_GPMI_CTRL0_CS) & \ + (GPMI_IS_MX23((x)) \ + ? MX23_BM_GPMI_CTRL0_CS \ + : MX28_BM_GPMI_CTRL0_CS)) + +#define BP_GPMI_CTRL0_ADDRESS 17 +#define BM_GPMI_CTRL0_ADDRESS (3 << BP_GPMI_CTRL0_ADDRESS) +#define BF_GPMI_CTRL0_ADDRESS(v) \ + (((v) << BP_GPMI_CTRL0_ADDRESS) & BM_GPMI_CTRL0_ADDRESS) +#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0 +#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1 +#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2 + +#define BM_GPMI_CTRL0_ADDRESS_INCREMENT (1 << 16) +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED 0x0 +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED 0x1 + +#define BP_GPMI_CTRL0_XFER_COUNT 0 +#define BM_GPMI_CTRL0_XFER_COUNT (0xffff << BP_GPMI_CTRL0_XFER_COUNT) +#define BF_GPMI_CTRL0_XFER_COUNT(v) \ + (((v) << BP_GPMI_CTRL0_XFER_COUNT) & BM_GPMI_CTRL0_XFER_COUNT) + +#define HW_GPMI_COMPARE 0x00000010 + +#define HW_GPMI_ECCCTRL 0x00000020 +#define HW_GPMI_ECCCTRL_SET 0x00000024 +#define HW_GPMI_ECCCTRL_CLR 0x00000028 +#define HW_GPMI_ECCCTRL_TOG 0x0000002c + +#define BP_GPMI_ECCCTRL_ECC_CMD 13 +#define BM_GPMI_ECCCTRL_ECC_CMD (3 << BP_GPMI_ECCCTRL_ECC_CMD) +#define BF_GPMI_ECCCTRL_ECC_CMD(v) \ + (((v) << BP_GPMI_ECCCTRL_ECC_CMD) & BM_GPMI_ECCCTRL_ECC_CMD) +#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE 0x0 +#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE 0x1 + +#define BM_GPMI_ECCCTRL_ENABLE_ECC (1 << 12) +#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE 0x1 +#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE 0x0 + +#define BP_GPMI_ECCCTRL_BUFFER_MASK 0 +#define BM_GPMI_ECCCTRL_BUFFER_MASK (0x1ff << BP_GPMI_ECCCTRL_BUFFER_MASK) +#define BF_GPMI_ECCCTRL_BUFFER_MASK(v) \ + (((v) << BP_GPMI_ECCCTRL_BUFFER_MASK) & BM_GPMI_ECCCTRL_BUFFER_MASK) +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF + +#define HW_GPMI_ECCCOUNT 0x00000030 +#define HW_GPMI_PAYLOAD 0x00000040 +#define HW_GPMI_AUXILIARY 0x00000050 +#define HW_GPMI_CTRL1 0x00000060 +#define HW_GPMI_CTRL1_SET 0x00000064 +#define HW_GPMI_CTRL1_CLR 0x00000068 +#define HW_GPMI_CTRL1_TOG 0x0000006c + +#define BM_GPMI_CTRL1_BCH_MODE (1 << 18) + +#define BP_GPMI_CTRL1_DLL_ENABLE 17 +#define BM_GPMI_CTRL1_DLL_ENABLE (1 << BP_GPMI_CTRL1_DLL_ENABLE) + +#define BP_GPMI_CTRL1_HALF_PERIOD 16 +#define BM_GPMI_CTRL1_HALF_PERIOD (1 << BP_GPMI_CTRL1_HALF_PERIOD) + +#define BP_GPMI_CTRL1_RDN_DELAY 12 +#define BM_GPMI_CTRL1_RDN_DELAY (0xf << BP_GPMI_CTRL1_RDN_DELAY) +#define BF_GPMI_CTRL1_RDN_DELAY(v) \ + (((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY) + +#define BM_GPMI_CTRL1_DEV_RESET (1 << 3) +#define BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0 +#define BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1 + +#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY (1 << 2) +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0 +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1 + +#define BM_GPMI_CTRL1_CAMERA_MODE (1 << 1) +#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0 +#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1 + +#define BM_GPMI_CTRL1_GPMI_MODE (1 << 0) + +#define HW_GPMI_TIMING0 0x00000070 + +#define BP_GPMI_TIMING0_ADDRESS_SETUP 16 +#define BM_GPMI_TIMING0_ADDRESS_SETUP (0xff << BP_GPMI_TIMING0_ADDRESS_SETUP) +#define BF_GPMI_TIMING0_ADDRESS_SETUP(v) \ + (((v) << BP_GPMI_TIMING0_ADDRESS_SETUP) & BM_GPMI_TIMING0_ADDRESS_SETUP) + +#define BP_GPMI_TIMING0_DATA_HOLD 8 +#define BM_GPMI_TIMING0_DATA_HOLD (0xff << BP_GPMI_TIMING0_DATA_HOLD) +#define BF_GPMI_TIMING0_DATA_HOLD(v) \ + (((v) << BP_GPMI_TIMING0_DATA_HOLD) & BM_GPMI_TIMING0_DATA_HOLD) + +#define BP_GPMI_TIMING0_DATA_SETUP 0 +#define BM_GPMI_TIMING0_DATA_SETUP (0xff << BP_GPMI_TIMING0_DATA_SETUP) +#define BF_GPMI_TIMING0_DATA_SETUP(v) \ + (((v) << BP_GPMI_TIMING0_DATA_SETUP) & BM_GPMI_TIMING0_DATA_SETUP) + +#define HW_GPMI_TIMING1 0x00000080 +#define BP_GPMI_TIMING1_BUSY_TIMEOUT 16 + +#define HW_GPMI_TIMING2 0x00000090 +#define HW_GPMI_DATA 0x000000a0 + +/* MX28 uses this to detect READY. */ +#define HW_GPMI_STAT 0x000000b0 +#define MX28_BP_GPMI_STAT_READY_BUSY 24 +#define MX28_BM_GPMI_STAT_READY_BUSY (0xff << MX28_BP_GPMI_STAT_READY_BUSY) +#define MX28_BF_GPMI_STAT_READY_BUSY(v) \ + (((v) << MX28_BP_GPMI_STAT_READY_BUSY) & MX28_BM_GPMI_STAT_READY_BUSY) + +/* MX23 uses this to detect READY. */ +#define HW_GPMI_DEBUG 0x000000c0 +#define MX23_BP_GPMI_DEBUG_READY0 28 +#define MX23_BM_GPMI_DEBUG_READY0 (1 << MX23_BP_GPMI_DEBUG_READY0) +#endif From 157550ff77cb5087033382782f4e856094466c16 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 8 Sep 2011 10:47:11 +0800 Subject: [PATCH 0327/1596] mtd: add GPMI-NAND driver in the config and Makefile add the GPMI-NAND driver in the relevant Kconfig and Makefile in the MTD. Signed-off-by: Huang Shijie Acked-by: Marek Vasut Tested-by: Koen Beel Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/Kconfig | 13 +++++++++++++ drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/gpmi-nand/Makefile | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 drivers/mtd/nand/gpmi-nand/Makefile diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 7ec5b494583f..42b7b861c74a 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -417,6 +417,19 @@ config MTD_NAND_NANDSIM The simulator may simulate various NAND flash chips for the MTD nand layer. +config MTD_NAND_GPMI_NAND + bool "GPMI NAND Flash Controller driver" + depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28) + select MTD_PARTITIONS + select MTD_CMDLINE_PARTS + help + Enables NAND Flash support for IMX23 or IMX28. + The GPMI controller is very powerful, with the help of BCH + module, it can do the hardware ECC. The GPMI supports several + NAND flashs at the same time. The GPMI may conflicts with other + block, such as SD card. So pay attention to it when you enable + the GPMI. + config MTD_NAND_PLATFORM tristate "Support for generic platform NAND driver" help diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index c9334e9af912..618f4ba23699 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -48,5 +48,6 @@ obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o +obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/gpmi-nand/Makefile b/drivers/mtd/nand/gpmi-nand/Makefile new file mode 100644 index 000000000000..3a462487c35e --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o +gpmi_nand-objs += gpmi-nand.o +gpmi_nand-objs += gpmi-lib.o From 10a2bcae99267b28e058b089fda30de7397b69f5 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 8 Sep 2011 10:47:09 +0800 Subject: [PATCH 0328/1596] mtd: add the common code for GPMI-NAND controller driver These files contain the common code for the GPMI-NAND driver. Signed-off-by: Huang Shijie Acked-by: Marek Vasut Tested-by: Koen Beel Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 1619 ++++++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 273 ++++ 2 files changed, 1892 insertions(+) create mode 100644 drivers/mtd/nand/gpmi-nand/gpmi-nand.c create mode 100644 drivers/mtd/nand/gpmi-nand/gpmi-nand.h diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c new file mode 100644 index 000000000000..5c0fe0dd7057 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -0,0 +1,1619 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include +#include +#include +#include +#include + +#include "gpmi-nand.h" + +/* add our owner bbt descriptor */ +static uint8_t scan_ff_pattern[] = { 0xff }; +static struct nand_bbt_descr gpmi_bbt_descr = { + .options = 0, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern +}; + +/* We will use all the (page + OOB). */ +static struct nand_ecclayout gpmi_hw_ecclayout = { + .eccbytes = 0, + .eccpos = { 0, }, + .oobfree = { {.offset = 0, .length = 0} } +}; + +static irqreturn_t bch_irq(int irq, void *cookie) +{ + struct gpmi_nand_data *this = cookie; + + gpmi_clear_bch(this); + complete(&this->bch_done); + return IRQ_HANDLED; +} + +/* + * Calculate the ECC strength by hand: + * E : The ECC strength. + * G : the length of Galois Field. + * N : The chunk count of per page. + * O : the oobsize of the NAND chip. + * M : the metasize of per page. + * + * The formula is : + * E * G * N + * ------------ <= (O - M) + * 8 + * + * So, we get E by: + * (O - M) * 8 + * E <= ------------- + * G * N + */ +static inline int get_ecc_strength(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct mtd_info *mtd = &this->mtd; + int ecc_strength; + + ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8) + / (geo->gf_len * geo->ecc_chunk_count); + + /* We need the minor even number. */ + return round_down(ecc_strength, 2); +} + +int common_nfc_set_geometry(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct mtd_info *mtd = &this->mtd; + unsigned int metadata_size; + unsigned int status_size; + unsigned int block_mark_bit_offset; + + /* + * The size of the metadata can be changed, though we set it to 10 + * bytes now. But it can't be too large, because we have to save + * enough space for BCH. + */ + geo->metadata_size = 10; + + /* The default for the length of Galois Field. */ + geo->gf_len = 13; + + /* The default for chunk size. There is no oobsize greater then 512. */ + geo->ecc_chunk_size = 512; + while (geo->ecc_chunk_size < mtd->oobsize) + geo->ecc_chunk_size *= 2; /* keep C >= O */ + + geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; + + /* We use the same ECC strength for all chunks. */ + geo->ecc_strength = get_ecc_strength(this); + if (!geo->ecc_strength) { + pr_err("We get a wrong ECC strength.\n"); + return -EINVAL; + } + + geo->page_size = mtd->writesize + mtd->oobsize; + geo->payload_size = mtd->writesize; + + /* + * The auxiliary buffer contains the metadata and the ECC status. The + * metadata is padded to the nearest 32-bit boundary. The ECC status + * contains one byte for every ECC chunk, and is also padded to the + * nearest 32-bit boundary. + */ + metadata_size = ALIGN(geo->metadata_size, 4); + status_size = ALIGN(geo->ecc_chunk_count, 4); + + geo->auxiliary_size = metadata_size + status_size; + geo->auxiliary_status_offset = metadata_size; + + if (!this->swap_block_mark) + return 0; + + /* + * We need to compute the byte and bit offsets of + * the physical block mark within the ECC-based view of the page. + * + * NAND chip with 2K page shows below: + * (Block Mark) + * | | + * | D | + * |<---->| + * V V + * +---+----------+-+----------+-+----------+-+----------+-+ + * | M | data |E| data |E| data |E| data |E| + * +---+----------+-+----------+-+----------+-+----------+-+ + * + * The position of block mark moves forward in the ECC-based view + * of page, and the delta is: + * + * E * G * (N - 1) + * D = (---------------- + M) + * 8 + * + * With the formula to compute the ECC strength, and the condition + * : C >= O (C is the ecc chunk size) + * + * It's easy to deduce to the following result: + * + * E * G (O - M) C - M C - M + * ----------- <= ------- <= -------- < --------- + * 8 N N (N - 1) + * + * So, we get: + * + * E * G * (N - 1) + * D = (---------------- + M) < C + * 8 + * + * The above inequality means the position of block mark + * within the ECC-based view of the page is still in the data chunk, + * and it's NOT in the ECC bits of the chunk. + * + * Use the following to compute the bit position of the + * physical block mark within the ECC-based view of the page: + * (page_size - D) * 8 + * + * --Huang Shijie + */ + block_mark_bit_offset = mtd->writesize * 8 - + (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1) + + geo->metadata_size * 8); + + geo->block_mark_byte_offset = block_mark_bit_offset / 8; + geo->block_mark_bit_offset = block_mark_bit_offset % 8; + return 0; +} + +struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) +{ + int chipnr = this->current_chip; + + return this->dma_chans[chipnr]; +} + +/* Can we use the upper's buffer directly for DMA? */ +void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) +{ + struct scatterlist *sgl = &this->data_sgl; + int ret; + + this->direct_dma_map_ok = true; + + /* first try to map the upper buffer directly */ + sg_init_one(sgl, this->upper_buf, this->upper_len); + ret = dma_map_sg(this->dev, sgl, 1, dr); + if (ret == 0) { + /* We have to use our own DMA buffer. */ + sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE); + + if (dr == DMA_TO_DEVICE) + memcpy(this->data_buffer_dma, this->upper_buf, + this->upper_len); + + ret = dma_map_sg(this->dev, sgl, 1, dr); + if (ret == 0) + pr_err("map failed.\n"); + + this->direct_dma_map_ok = false; + } +} + +/* This will be called after the DMA operation is finished. */ +static void dma_irq_callback(void *param) +{ + struct gpmi_nand_data *this = param; + struct completion *dma_c = &this->dma_done; + + complete(dma_c); + + switch (this->dma_type) { + case DMA_FOR_COMMAND: + dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE); + break; + + case DMA_FOR_READ_DATA: + dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE); + if (this->direct_dma_map_ok == false) + memcpy(this->upper_buf, this->data_buffer_dma, + this->upper_len); + break; + + case DMA_FOR_WRITE_DATA: + dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE); + break; + + case DMA_FOR_READ_ECC_PAGE: + case DMA_FOR_WRITE_ECC_PAGE: + /* We have to wait the BCH interrupt to finish. */ + break; + + default: + pr_err("in wrong DMA operation.\n"); + } +} + +int start_dma_without_bch_irq(struct gpmi_nand_data *this, + struct dma_async_tx_descriptor *desc) +{ + struct completion *dma_c = &this->dma_done; + int err; + + init_completion(dma_c); + + desc->callback = dma_irq_callback; + desc->callback_param = this; + dmaengine_submit(desc); + + /* Wait for the interrupt from the DMA block. */ + err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); + if (!err) { + pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type); + gpmi_dump_info(this); + return -ETIMEDOUT; + } + return 0; +} + +/* + * This function is used in BCH reading or BCH writing pages. + * It will wait for the BCH interrupt as long as ONE second. + * Actually, we must wait for two interrupts : + * [1] firstly the DMA interrupt and + * [2] secondly the BCH interrupt. + */ +int start_dma_with_bch_irq(struct gpmi_nand_data *this, + struct dma_async_tx_descriptor *desc) +{ + struct completion *bch_c = &this->bch_done; + int err; + + /* Prepare to receive an interrupt from the BCH block. */ + init_completion(bch_c); + + /* start the DMA */ + start_dma_without_bch_irq(this, desc); + + /* Wait for the interrupt from the BCH block. */ + err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); + if (!err) { + pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type); + gpmi_dump_info(this); + return -ETIMEDOUT; + } + return 0; +} + +static int __devinit +acquire_register_block(struct gpmi_nand_data *this, const char *res_name) +{ + struct platform_device *pdev = this->pdev; + struct resources *res = &this->resources; + struct resource *r; + void *p; + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); + if (!r) { + pr_err("Can't get resource for %s\n", res_name); + return -ENXIO; + } + + p = ioremap(r->start, resource_size(r)); + if (!p) { + pr_err("Can't remap %s\n", res_name); + return -ENOMEM; + } + + if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME)) + res->gpmi_regs = p; + else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME)) + res->bch_regs = p; + else + pr_err("unknown resource name : %s\n", res_name); + + return 0; +} + +static void release_register_block(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + if (res->gpmi_regs) + iounmap(res->gpmi_regs); + if (res->bch_regs) + iounmap(res->bch_regs); + res->gpmi_regs = NULL; + res->bch_regs = NULL; +} + +static int __devinit +acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) +{ + struct platform_device *pdev = this->pdev; + struct resources *res = &this->resources; + const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; + struct resource *r; + int err; + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); + if (!r) { + pr_err("Can't get resource for %s\n", res_name); + return -ENXIO; + } + + err = request_irq(r->start, irq_h, 0, res_name, this); + if (err) { + pr_err("Can't own %s\n", res_name); + return err; + } + + res->bch_low_interrupt = r->start; + res->bch_high_interrupt = r->end; + return 0; +} + +static void release_bch_irq(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + int i = res->bch_low_interrupt; + + for (; i <= res->bch_high_interrupt; i++) + free_irq(i, this); +} + +static bool gpmi_dma_filter(struct dma_chan *chan, void *param) +{ + struct gpmi_nand_data *this = param; + struct resource *r = this->private; + + if (!mxs_dma_is_apbh(chan)) + return false; + /* + * only catch the GPMI dma channels : + * for mx23 : MX23_DMA_GPMI0 ~ MX23_DMA_GPMI3 + * (These four channels share the same IRQ!) + * + * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 + * (These eight channels share the same IRQ!) + */ + if (r->start <= chan->chan_id && chan->chan_id <= r->end) { + chan->private = &this->dma_data; + return true; + } + return false; +} + +static void release_dma_channels(struct gpmi_nand_data *this) +{ + unsigned int i; + for (i = 0; i < DMA_CHANS; i++) + if (this->dma_chans[i]) { + dma_release_channel(this->dma_chans[i]); + this->dma_chans[i] = NULL; + } +} + +static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) +{ + struct platform_device *pdev = this->pdev; + struct gpmi_nand_platform_data *pdata = this->pdata; + struct resources *res = &this->resources; + struct resource *r, *r_dma; + unsigned int i; + + r = platform_get_resource_byname(pdev, IORESOURCE_DMA, + GPMI_NAND_DMA_CHANNELS_RES_NAME); + r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + GPMI_NAND_DMA_INTERRUPT_RES_NAME); + if (!r || !r_dma) { + pr_err("Can't get resource for DMA\n"); + return -ENXIO; + } + + /* used in gpmi_dma_filter() */ + this->private = r; + + for (i = r->start; i <= r->end; i++) { + struct dma_chan *dma_chan; + dma_cap_mask_t mask; + + if (i - r->start >= pdata->max_chip_count) + break; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* get the DMA interrupt */ + if (r_dma->start == r_dma->end) { + /* only register the first. */ + if (i == r->start) + this->dma_data.chan_irq = r_dma->start; + else + this->dma_data.chan_irq = NO_IRQ; + } else + this->dma_data.chan_irq = r_dma->start + (i - r->start); + + dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); + if (!dma_chan) + goto acquire_err; + + /* fill the first empty item */ + this->dma_chans[i - r->start] = dma_chan; + } + + res->dma_low_channel = r->start; + res->dma_high_channel = i; + return 0; + +acquire_err: + pr_err("Can't acquire DMA channel %u\n", i); + release_dma_channels(this); + return -EINVAL; +} + +static int __devinit acquire_resources(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + int ret; + + ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME); + if (ret) + goto exit_regs; + + ret = acquire_register_block(this, GPMI_NAND_BCH_REGS_ADDR_RES_NAME); + if (ret) + goto exit_regs; + + ret = acquire_bch_irq(this, bch_irq); + if (ret) + goto exit_regs; + + ret = acquire_dma_channels(this); + if (ret) + goto exit_dma_channels; + + res->clock = clk_get(&this->pdev->dev, NULL); + if (IS_ERR(res->clock)) { + pr_err("can not get the clock\n"); + ret = -ENOENT; + goto exit_clock; + } + return 0; + +exit_clock: + release_dma_channels(this); +exit_dma_channels: + release_bch_irq(this); +exit_regs: + release_register_block(this); + return ret; +} + +static void release_resources(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + + clk_put(r->clock); + release_register_block(this); + release_bch_irq(this); + release_dma_channels(this); +} + +static int __devinit init_hardware(struct gpmi_nand_data *this) +{ + int ret; + + /* + * This structure contains the "safe" GPMI timing that should succeed + * with any NAND Flash device + * (although, with less-than-optimal performance). + */ + struct nand_timing safe_timing = { + .data_setup_in_ns = 80, + .data_hold_in_ns = 60, + .address_setup_in_ns = 25, + .gpmi_sample_delay_in_ns = 6, + .tREA_in_ns = -1, + .tRLOH_in_ns = -1, + .tRHOH_in_ns = -1, + }; + + /* Initialize the hardwares. */ + ret = gpmi_init(this); + if (ret) + return ret; + + this->timing = safe_timing; + return 0; +} + +static int read_page_prepare(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void **use_virt, dma_addr_t *use_phys) +{ + struct device *dev = this->dev; + + if (virt_addr_valid(destination)) { + dma_addr_t dest_phys; + + dest_phys = dma_map_single(dev, destination, + length, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, dest_phys)) { + if (alt_size < length) { + pr_err("Alternate buffer is too small\n"); + return -ENOMEM; + } + goto map_failed; + } + *use_virt = destination; + *use_phys = dest_phys; + this->direct_dma_map_ok = true; + return 0; + } + +map_failed: + *use_virt = alt_virt; + *use_phys = alt_phys; + this->direct_dma_map_ok = false; + return 0; +} + +static inline void read_page_end(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void *used_virt, dma_addr_t used_phys) +{ + if (this->direct_dma_map_ok) + dma_unmap_single(this->dev, used_phys, length, DMA_FROM_DEVICE); +} + +static inline void read_page_swap_end(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void *used_virt, dma_addr_t used_phys) +{ + if (!this->direct_dma_map_ok) + memcpy(destination, alt_virt, length); +} + +static int send_page_prepare(struct gpmi_nand_data *this, + const void *source, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + const void **use_virt, dma_addr_t *use_phys) +{ + struct device *dev = this->dev; + + if (virt_addr_valid(source)) { + dma_addr_t source_phys; + + source_phys = dma_map_single(dev, (void *)source, length, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, source_phys)) { + if (alt_size < length) { + pr_err("Alternate buffer is too small\n"); + return -ENOMEM; + } + goto map_failed; + } + *use_virt = source; + *use_phys = source_phys; + return 0; + } +map_failed: + /* + * Copy the content of the source buffer into the alternate + * buffer and set up the return values accordingly. + */ + memcpy(alt_virt, source, length); + + *use_virt = alt_virt; + *use_phys = alt_phys; + return 0; +} + +static void send_page_end(struct gpmi_nand_data *this, + const void *source, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + const void *used_virt, dma_addr_t used_phys) +{ + struct device *dev = this->dev; + if (used_virt == source) + dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE); +} + +static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + + if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt)) + dma_free_coherent(dev, this->page_buffer_size, + this->page_buffer_virt, + this->page_buffer_phys); + kfree(this->cmd_buffer); + kfree(this->data_buffer_dma); + + this->cmd_buffer = NULL; + this->data_buffer_dma = NULL; + this->page_buffer_virt = NULL; + this->page_buffer_size = 0; +} + +/* Allocate the DMA buffers */ +static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct device *dev = this->dev; + + /* [1] Allocate a command buffer. PAGE_SIZE is enough. */ + this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA); + if (this->cmd_buffer == NULL) + goto error_alloc; + + /* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */ + this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA); + if (this->data_buffer_dma == NULL) + goto error_alloc; + + /* + * [3] Allocate the page buffer. + * + * Both the payload buffer and the auxiliary buffer must appear on + * 32-bit boundaries. We presume the size of the payload buffer is a + * power of two and is much larger than four, which guarantees the + * auxiliary buffer will appear on a 32-bit boundary. + */ + this->page_buffer_size = geo->payload_size + geo->auxiliary_size; + this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size, + &this->page_buffer_phys, GFP_DMA); + if (!this->page_buffer_virt) + goto error_alloc; + + + /* Slice up the page buffer. */ + this->payload_virt = this->page_buffer_virt; + this->payload_phys = this->page_buffer_phys; + this->auxiliary_virt = this->payload_virt + geo->payload_size; + this->auxiliary_phys = this->payload_phys + geo->payload_size; + return 0; + +error_alloc: + gpmi_free_dma_buffer(this); + pr_err("allocate DMA buffer ret!!\n"); + return -ENOMEM; +} + +static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int ret; + + /* + * Every operation begins with a command byte and a series of zero or + * more address bytes. These are distinguished by either the Address + * Latch Enable (ALE) or Command Latch Enable (CLE) signals being + * asserted. When MTD is ready to execute the command, it will deassert + * both latch enables. + * + * Rather than run a separate DMA operation for every single byte, we + * queue them up and run a single DMA operation for the entire series + * of command and data bytes. NAND_CMD_NONE means the END of the queue. + */ + if ((ctrl & (NAND_ALE | NAND_CLE))) { + if (data != NAND_CMD_NONE) + this->cmd_buffer[this->command_length++] = data; + return; + } + + if (!this->command_length) + return; + + ret = gpmi_send_command(this); + if (ret) + pr_err("Chip: %u, Error %d\n", this->current_chip, ret); + + this->command_length = 0; +} + +static int gpmi_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + return gpmi_is_ready(this, this->current_chip); +} + +static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + if ((this->current_chip < 0) && (chipnr >= 0)) + gpmi_begin(this); + else if ((this->current_chip >= 0) && (chipnr < 0)) + gpmi_end(this); + + this->current_chip = chipnr; +} + +static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + pr_debug("len is %d\n", len); + this->upper_buf = buf; + this->upper_len = len; + + gpmi_read_data(this); +} + +static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + pr_debug("len is %d\n", len); + this->upper_buf = (uint8_t *)buf; + this->upper_len = len; + + gpmi_send_data(this); +} + +static uint8_t gpmi_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + uint8_t *buf = this->data_buffer_dma; + + gpmi_read_buf(mtd, buf, 1); + return buf[0]; +} + +/* + * Handles block mark swapping. + * It can be called in swapping the block mark, or swapping it back, + * because the the operations are the same. + */ +static void block_mark_swapping(struct gpmi_nand_data *this, + void *payload, void *auxiliary) +{ + struct bch_geometry *nfc_geo = &this->bch_geometry; + unsigned char *p; + unsigned char *a; + unsigned int bit; + unsigned char mask; + unsigned char from_data; + unsigned char from_oob; + + if (!this->swap_block_mark) + return; + + /* + * If control arrives here, we're swapping. Make some convenience + * variables. + */ + bit = nfc_geo->block_mark_bit_offset; + p = payload + nfc_geo->block_mark_byte_offset; + a = auxiliary; + + /* + * Get the byte from the data area that overlays the block mark. Since + * the ECC engine applies its own view to the bits in the page, the + * physical block mark won't (in general) appear on a byte boundary in + * the data. + */ + from_data = (p[0] >> bit) | (p[1] << (8 - bit)); + + /* Get the byte from the OOB. */ + from_oob = a[0]; + + /* Swap them. */ + a[0] = from_data; + + mask = (0x1 << bit) - 1; + p[0] = (p[0] & mask) | (from_oob << bit); + + mask = ~0 << bit; + p[1] = (p[1] & mask) | (from_oob >> (8 - bit)); +} + +static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + void *payload_virt; + dma_addr_t payload_phys; + void *auxiliary_virt; + dma_addr_t auxiliary_phys; + unsigned int i; + unsigned char *status; + unsigned int failed; + unsigned int corrected; + int ret; + + pr_debug("page number is : %d\n", page); + ret = read_page_prepare(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + &payload_virt, &payload_phys); + if (ret) { + pr_err("Inadequate DMA buffer\n"); + ret = -ENOMEM; + return ret; + } + auxiliary_virt = this->auxiliary_virt; + auxiliary_phys = this->auxiliary_phys; + + /* go! */ + ret = gpmi_read_page(this, payload_phys, auxiliary_phys); + read_page_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); + if (ret) { + pr_err("Error in ECC-based read: %d\n", ret); + goto exit_nfc; + } + + /* handle the block mark swapping */ + block_mark_swapping(this, payload_virt, auxiliary_virt); + + /* Loop over status bytes, accumulating ECC status. */ + failed = 0; + corrected = 0; + status = auxiliary_virt + nfc_geo->auxiliary_status_offset; + + for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) { + if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED)) + continue; + + if (*status == STATUS_UNCORRECTABLE) { + failed++; + continue; + } + corrected += *status; + } + + /* + * Propagate ECC status to the owning MTD only when failed or + * corrected times nearly reaches our ECC correction threshold. + */ + if (failed || corrected >= (nfc_geo->ecc_strength - 1)) { + mtd->ecc_stats.failed += failed; + mtd->ecc_stats.corrected += corrected; + } + + /* + * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for + * details about our policy for delivering the OOB. + * + * We fill the caller's buffer with set bits, and then copy the block + * mark to th caller's buffer. Note that, if block mark swapping was + * necessary, it has already been done, so we can rely on the first + * byte of the auxiliary buffer to contain the block mark. + */ + memset(chip->oob_poi, ~0, mtd->oobsize); + chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; + + read_page_swap_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); +exit_nfc: + return ret; +} + +static void gpmi_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + const void *payload_virt; + dma_addr_t payload_phys; + const void *auxiliary_virt; + dma_addr_t auxiliary_phys; + int ret; + + pr_debug("ecc write page.\n"); + if (this->swap_block_mark) { + /* + * If control arrives here, we're doing block mark swapping. + * Since we can't modify the caller's buffers, we must copy them + * into our own. + */ + memcpy(this->payload_virt, buf, mtd->writesize); + payload_virt = this->payload_virt; + payload_phys = this->payload_phys; + + memcpy(this->auxiliary_virt, chip->oob_poi, + nfc_geo->auxiliary_size); + auxiliary_virt = this->auxiliary_virt; + auxiliary_phys = this->auxiliary_phys; + + /* Handle block mark swapping. */ + block_mark_swapping(this, + (void *) payload_virt, (void *) auxiliary_virt); + } else { + /* + * If control arrives here, we're not doing block mark swapping, + * so we can to try and use the caller's buffers. + */ + ret = send_page_prepare(this, + buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + &payload_virt, &payload_phys); + if (ret) { + pr_err("Inadequate payload DMA buffer\n"); + return; + } + + ret = send_page_prepare(this, + chip->oob_poi, mtd->oobsize, + this->auxiliary_virt, this->auxiliary_phys, + nfc_geo->auxiliary_size, + &auxiliary_virt, &auxiliary_phys); + if (ret) { + pr_err("Inadequate auxiliary DMA buffer\n"); + goto exit_auxiliary; + } + } + + /* Ask the NFC. */ + ret = gpmi_send_page(this, payload_phys, auxiliary_phys); + if (ret) + pr_err("Error in ECC-based write: %d\n", ret); + + if (!this->swap_block_mark) { + send_page_end(this, chip->oob_poi, mtd->oobsize, + this->auxiliary_virt, this->auxiliary_phys, + nfc_geo->auxiliary_size, + auxiliary_virt, auxiliary_phys); +exit_auxiliary: + send_page_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); + } +} + +/* + * There are several places in this driver where we have to handle the OOB and + * block marks. This is the function where things are the most complicated, so + * this is where we try to explain it all. All the other places refer back to + * here. + * + * These are the rules, in order of decreasing importance: + * + * 1) Nothing the caller does can be allowed to imperil the block mark. + * + * 2) In read operations, the first byte of the OOB we return must reflect the + * true state of the block mark, no matter where that block mark appears in + * the physical page. + * + * 3) ECC-based read operations return an OOB full of set bits (since we never + * allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads + * return). + * + * 4) "Raw" read operations return a direct view of the physical bytes in the + * page, using the conventional definition of which bytes are data and which + * are OOB. This gives the caller a way to see the actual, physical bytes + * in the page, without the distortions applied by our ECC engine. + * + * + * What we do for this specific read operation depends on two questions: + * + * 1) Are we doing a "raw" read, or an ECC-based read? + * + * 2) Are we using block mark swapping or transcription? + * + * There are four cases, illustrated by the following Karnaugh map: + * + * | Raw | ECC-based | + * -------------+-------------------------+-------------------------+ + * | Read the conventional | | + * | OOB at the end of the | | + * Swapping | page and return it. It | | + * | contains exactly what | | + * | we want. | Read the block mark and | + * -------------+-------------------------+ return it in a buffer | + * | Read the conventional | full of set bits. | + * | OOB at the end of the | | + * | page and also the block | | + * Transcribing | mark in the metadata. | | + * | Copy the block mark | | + * | into the first byte of | | + * | the OOB. | | + * -------------+-------------------------+-------------------------+ + * + * Note that we break rule #4 in the Transcribing/Raw case because we're not + * giving an accurate view of the actual, physical bytes in the page (we're + * overwriting the block mark). That's OK because it's more important to follow + * rule #2. + * + * It turns out that knowing whether we want an "ECC-based" or "raw" read is not + * easy. When reading a page, for example, the NAND Flash MTD code calls our + * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an + * ECC-based or raw view of the page is implicit in which function it calls + * (there is a similar pair of ECC-based/raw functions for writing). + * + * Since MTD assumes the OOB is not covered by ECC, there is no pair of + * ECC-based/raw functions for reading or or writing the OOB. The fact that the + * caller wants an ECC-based or raw view of the page is not propagated down to + * this driver. + */ +static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + struct gpmi_nand_data *this = chip->priv; + + pr_debug("page number is %d\n", page); + /* clear the OOB buffer */ + memset(chip->oob_poi, ~0, mtd->oobsize); + + /* Read out the conventional OOB. */ + chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* + * Now, we want to make sure the block mark is correct. In the + * Swapping/Raw case, we already have it. Otherwise, we need to + * explicitly read it. + */ + if (!this->swap_block_mark) { + /* Read the block mark into the first byte of the OOB buffer. */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + chip->oob_poi[0] = chip->read_byte(mtd); + } + + /* + * Return true, indicating that the next call to this function must send + * a command. + */ + return true; +} + +static int +gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ + /* + * The BCH will use all the (page + oob). + * Our gpmi_hw_ecclayout can only prohibit the JFFS2 to write the oob. + * But it can not stop some ioctls such MEMWRITEOOB which uses + * MTD_OOB_PLACE. So We have to implement this function to prohibit + * these ioctls too. + */ + return -EPERM; +} + +static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int block, ret = 0; + uint8_t *block_mark; + int column, page, status, chipnr; + + /* Get block number */ + block = (int)(ofs >> chip->bbt_erase_shift); + if (chip->bbt) + chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + + /* Do we have a flash based bad block table ? */ + if (chip->options & NAND_BBT_USE_FLASH) + ret = nand_update_bbt(mtd, ofs); + else { + chipnr = (int)(ofs >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + column = this->swap_block_mark ? mtd->writesize : 0; + + /* Write the block mark. */ + block_mark = this->data_buffer_dma; + block_mark[0] = 0; /* bad block marker */ + + /* Shift to get page */ + page = (int)(ofs >> chip->page_shift); + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); + chip->write_buf(mtd, block_mark, 1); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + ret = -EIO; + + chip->select_chip(mtd, -1); + } + if (!ret) + mtd->ecc_stats.badblocks++; + + return ret; +} + +static int __devinit nand_boot_set_geometry(struct gpmi_nand_data *this) +{ + struct boot_rom_geometry *geometry = &this->rom_geometry; + + /* + * Set the boot block stride size. + * + * In principle, we should be reading this from the OTP bits, since + * that's where the ROM is going to get it. In fact, we don't have any + * way to read the OTP bits, so we go with the default and hope for the + * best. + */ + geometry->stride_size_in_pages = 64; + + /* + * Set the search area stride exponent. + * + * In principle, we should be reading this from the OTP bits, since + * that's where the ROM is going to get it. In fact, we don't have any + * way to read the OTP bits, so we go with the default and hope for the + * best. + */ + geometry->search_area_stride_exponent = 2; + return 0; +} + +static const char *fingerprint = "STMP"; +static int __devinit mx23_check_transcription_stamp(struct gpmi_nand_data *this) +{ + struct boot_rom_geometry *rom_geo = &this->rom_geometry; + struct device *dev = this->dev; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + unsigned int search_area_size_in_strides; + unsigned int stride; + unsigned int page; + loff_t byte; + uint8_t *buffer = chip->buffers->databuf; + int saved_chip_number; + int found_an_ncb_fingerprint = false; + + /* Compute the number of strides in a search area. */ + search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; + + saved_chip_number = this->current_chip; + chip->select_chip(mtd, 0); + + /* + * Loop through the first search area, looking for the NCB fingerprint. + */ + dev_dbg(dev, "Scanning for an NCB fingerprint...\n"); + + for (stride = 0; stride < search_area_size_in_strides; stride++) { + /* Compute the page and byte addresses. */ + page = stride * rom_geo->stride_size_in_pages; + byte = page * mtd->writesize; + + dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page); + + /* + * Read the NCB fingerprint. The fingerprint is four bytes long + * and starts in the 12th byte of the page. + */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 12, page); + chip->read_buf(mtd, buffer, strlen(fingerprint)); + + /* Look for the fingerprint. */ + if (!memcmp(buffer, fingerprint, strlen(fingerprint))) { + found_an_ncb_fingerprint = true; + break; + } + + } + + chip->select_chip(mtd, saved_chip_number); + + if (found_an_ncb_fingerprint) + dev_dbg(dev, "\tFound a fingerprint\n"); + else + dev_dbg(dev, "\tNo fingerprint found\n"); + return found_an_ncb_fingerprint; +} + +/* Writes a transcription stamp. */ +static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + struct boot_rom_geometry *rom_geo = &this->rom_geometry; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + unsigned int block_size_in_pages; + unsigned int search_area_size_in_strides; + unsigned int search_area_size_in_pages; + unsigned int search_area_size_in_blocks; + unsigned int block; + unsigned int stride; + unsigned int page; + loff_t byte; + uint8_t *buffer = chip->buffers->databuf; + int saved_chip_number; + int status; + + /* Compute the search area geometry. */ + block_size_in_pages = mtd->erasesize / mtd->writesize; + search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; + search_area_size_in_pages = search_area_size_in_strides * + rom_geo->stride_size_in_pages; + search_area_size_in_blocks = + (search_area_size_in_pages + (block_size_in_pages - 1)) / + block_size_in_pages; + + dev_dbg(dev, "Search Area Geometry :\n"); + dev_dbg(dev, "\tin Blocks : %u\n", search_area_size_in_blocks); + dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides); + dev_dbg(dev, "\tin Pages : %u\n", search_area_size_in_pages); + + /* Select chip 0. */ + saved_chip_number = this->current_chip; + chip->select_chip(mtd, 0); + + /* Loop over blocks in the first search area, erasing them. */ + dev_dbg(dev, "Erasing the search area...\n"); + + for (block = 0; block < search_area_size_in_blocks; block++) { + /* Compute the page address. */ + page = block * block_size_in_pages; + + /* Erase this block. */ + dev_dbg(dev, "\tErasing block 0x%x\n", block); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); + + /* Wait for the erase to finish. */ + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + dev_err(dev, "[%s] Erase failed.\n", __func__); + } + + /* Write the NCB fingerprint into the page buffer. */ + memset(buffer, ~0, mtd->writesize); + memset(chip->oob_poi, ~0, mtd->oobsize); + memcpy(buffer + 12, fingerprint, strlen(fingerprint)); + + /* Loop through the first search area, writing NCB fingerprints. */ + dev_dbg(dev, "Writing NCB fingerprints...\n"); + for (stride = 0; stride < search_area_size_in_strides; stride++) { + /* Compute the page and byte addresses. */ + page = stride * rom_geo->stride_size_in_pages; + byte = page * mtd->writesize; + + /* Write the first page of the current stride. */ + dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + chip->ecc.write_page_raw(mtd, chip, buffer); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + /* Wait for the write to finish. */ + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + dev_err(dev, "[%s] Write failed.\n", __func__); + } + + /* Deselect chip 0. */ + chip->select_chip(mtd, saved_chip_number); + return 0; +} + +static int __devinit mx23_boot_init(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + struct nand_chip *chip = &this->nand; + struct mtd_info *mtd = &this->mtd; + unsigned int block_count; + unsigned int block; + int chipnr; + int page; + loff_t byte; + uint8_t block_mark; + int ret = 0; + + /* + * If control arrives here, we can't use block mark swapping, which + * means we're forced to use transcription. First, scan for the + * transcription stamp. If we find it, then we don't have to do + * anything -- the block marks are already transcribed. + */ + if (mx23_check_transcription_stamp(this)) + return 0; + + /* + * If control arrives here, we couldn't find a transcription stamp, so + * so we presume the block marks are in the conventional location. + */ + dev_dbg(dev, "Transcribing bad block marks...\n"); + + /* Compute the number of blocks in the entire medium. */ + block_count = chip->chipsize >> chip->phys_erase_shift; + + /* + * Loop over all the blocks in the medium, transcribing block marks as + * we go. + */ + for (block = 0; block < block_count; block++) { + /* + * Compute the chip, page and byte addresses for this block's + * conventional mark. + */ + chipnr = block >> (chip->chip_shift - chip->phys_erase_shift); + page = block << (chip->phys_erase_shift - chip->page_shift); + byte = block << chip->phys_erase_shift; + + /* Send the command to read the conventional block mark. */ + chip->select_chip(mtd, chipnr); + chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + block_mark = chip->read_byte(mtd); + chip->select_chip(mtd, -1); + + /* + * Check if the block is marked bad. If so, we need to mark it + * again, but this time the result will be a mark in the + * location where we transcribe block marks. + */ + if (block_mark != 0xff) { + dev_dbg(dev, "Transcribing mark in block %u\n", block); + ret = chip->block_markbad(mtd, byte); + if (ret) + dev_err(dev, "Failed to mark block bad with " + "ret %d\n", ret); + } + } + + /* Write the stamp that indicates we've transcribed the block marks. */ + mx23_write_transcription_stamp(this); + return 0; +} + +static int __devinit nand_boot_init(struct gpmi_nand_data *this) +{ + nand_boot_set_geometry(this); + + /* This is ROM arch-specific initilization before the BBT scanning. */ + if (GPMI_IS_MX23(this)) + return mx23_boot_init(this); + return 0; +} + +static int __devinit gpmi_set_geometry(struct gpmi_nand_data *this) +{ + int ret; + + /* Free the temporary DMA memory for reading ID. */ + gpmi_free_dma_buffer(this); + + /* Set up the NFC geometry which is used by BCH. */ + ret = bch_set_geometry(this); + if (ret) { + pr_err("set geometry ret : %d\n", ret); + return ret; + } + + /* Alloc the new DMA buffers according to the pagesize and oobsize */ + return gpmi_alloc_dma_buffer(this); +} + +static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) +{ + int ret; + + /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ + if (GPMI_IS_MX23(this)) + this->swap_block_mark = false; + else + this->swap_block_mark = true; + + /* Set up the medium geometry */ + ret = gpmi_set_geometry(this); + if (ret) + return ret; + + /* NAND boot init, depends on the gpmi_set_geometry(). */ + return nand_boot_init(this); +} + +static int gpmi_scan_bbt(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int ret; + + /* Prepare for the BBT scan. */ + ret = gpmi_pre_bbt_scan(this); + if (ret) + return ret; + + /* use the default BBT implementation */ + return nand_default_bbt(mtd); +} + +void gpmi_nfc_exit(struct gpmi_nand_data *this) +{ + nand_release(&this->mtd); + gpmi_free_dma_buffer(this); +} + +static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) +{ + struct gpmi_nand_platform_data *pdata = this->pdata; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + int ret; + + /* init current chip */ + this->current_chip = -1; + + /* init the MTD data structures */ + mtd->priv = chip; + mtd->name = "gpmi-nand"; + mtd->owner = THIS_MODULE; + + /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */ + chip->priv = this; + chip->select_chip = gpmi_select_chip; + chip->cmd_ctrl = gpmi_cmd_ctrl; + chip->dev_ready = gpmi_dev_ready; + chip->read_byte = gpmi_read_byte; + chip->read_buf = gpmi_read_buf; + chip->write_buf = gpmi_write_buf; + chip->ecc.read_page = gpmi_ecc_read_page; + chip->ecc.write_page = gpmi_ecc_write_page; + chip->ecc.read_oob = gpmi_ecc_read_oob; + chip->ecc.write_oob = gpmi_ecc_write_oob; + chip->scan_bbt = gpmi_scan_bbt; + chip->badblock_pattern = &gpmi_bbt_descr; + chip->block_markbad = gpmi_block_markbad; + chip->options |= NAND_NO_SUBPAGE_WRITE; + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = 1; + chip->ecc.layout = &gpmi_hw_ecclayout; + + /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ + this->bch_geometry.payload_size = 1024; + this->bch_geometry.auxiliary_size = 128; + ret = gpmi_alloc_dma_buffer(this); + if (ret) + goto err_out; + + ret = nand_scan(mtd, pdata->max_chip_count); + if (ret) { + pr_err("Chip scan failed\n"); + goto err_out; + } + + ret = mtd_device_parse_register(mtd, NULL, NULL, + pdata->partitions, pdata->partition_count); + if (ret) + goto err_out; + return 0; + +err_out: + gpmi_nfc_exit(this); + return ret; +} + +static int __devinit gpmi_nand_probe(struct platform_device *pdev) +{ + struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data; + struct gpmi_nand_data *this; + int ret; + + this = kzalloc(sizeof(*this), GFP_KERNEL); + if (!this) { + pr_err("Failed to allocate per-device memory\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, this); + this->pdev = pdev; + this->dev = &pdev->dev; + this->pdata = pdata; + + if (pdata->platform_init) { + ret = pdata->platform_init(); + if (ret) + goto platform_init_error; + } + + ret = acquire_resources(this); + if (ret) + goto exit_acquire_resources; + + ret = init_hardware(this); + if (ret) + goto exit_nfc_init; + + ret = gpmi_nfc_init(this); + if (ret) + goto exit_nfc_init; + + return 0; + +exit_nfc_init: + release_resources(this); +platform_init_error: +exit_acquire_resources: + platform_set_drvdata(pdev, NULL); + kfree(this); + return ret; +} + +static int __exit gpmi_nand_remove(struct platform_device *pdev) +{ + struct gpmi_nand_data *this = platform_get_drvdata(pdev); + + gpmi_nfc_exit(this); + release_resources(this); + platform_set_drvdata(pdev, NULL); + kfree(this); + return 0; +} + +static const struct platform_device_id gpmi_ids[] = { + { + .name = "imx23-gpmi-nand", + .driver_data = IS_MX23, + }, { + .name = "imx28-gpmi-nand", + .driver_data = IS_MX28, + }, {}, +}; + +static struct platform_driver gpmi_nand_driver = { + .driver = { + .name = "gpmi-nand", + }, + .probe = gpmi_nand_probe, + .remove = __exit_p(gpmi_nand_remove), + .id_table = gpmi_ids, +}; + +static int __init gpmi_nand_init(void) +{ + int err; + + err = platform_driver_register(&gpmi_nand_driver); + if (err == 0) + printk(KERN_INFO "GPMI NAND driver registered. (IMX)\n"); + else + pr_err("i.MX GPMI NAND driver registration failed\n"); + return err; +} + +static void __exit gpmi_nand_exit(void) +{ + platform_driver_unregister(&gpmi_nand_driver); +} + +module_init(gpmi_nand_init); +module_exit(gpmi_nand_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h new file mode 100644 index 000000000000..e023bccb7781 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -0,0 +1,273 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H +#define __DRIVERS_MTD_NAND_GPMI_NAND_H + +#include +#include +#include +#include + +struct resources { + void *gpmi_regs; + void *bch_regs; + unsigned int bch_low_interrupt; + unsigned int bch_high_interrupt; + unsigned int dma_low_channel; + unsigned int dma_high_channel; + struct clk *clock; +}; + +/** + * struct bch_geometry - BCH geometry description. + * @gf_len: The length of Galois Field. (e.g., 13 or 14) + * @ecc_strength: A number that describes the strength of the ECC + * algorithm. + * @page_size: The size, in bytes, of a physical page, including + * both data and OOB. + * @metadata_size: The size, in bytes, of the metadata. + * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note + * the first chunk in the page includes both data and + * metadata, so it's a bit larger than this value. + * @ecc_chunk_count: The number of ECC chunks in the page, + * @payload_size: The size, in bytes, of the payload buffer. + * @auxiliary_size: The size, in bytes, of the auxiliary buffer. + * @auxiliary_status_offset: The offset into the auxiliary buffer at which + * the ECC status appears. + * @block_mark_byte_offset: The byte offset in the ECC-based page view at + * which the underlying physical block mark appears. + * @block_mark_bit_offset: The bit offset into the ECC-based page view at + * which the underlying physical block mark appears. + */ +struct bch_geometry { + unsigned int gf_len; + unsigned int ecc_strength; + unsigned int page_size; + unsigned int metadata_size; + unsigned int ecc_chunk_size; + unsigned int ecc_chunk_count; + unsigned int payload_size; + unsigned int auxiliary_size; + unsigned int auxiliary_status_offset; + unsigned int block_mark_byte_offset; + unsigned int block_mark_bit_offset; +}; + +/** + * struct boot_rom_geometry - Boot ROM geometry description. + * @stride_size_in_pages: The size of a boot block stride, in pages. + * @search_area_stride_exponent: The logarithm to base 2 of the size of a + * search area in boot block strides. + */ +struct boot_rom_geometry { + unsigned int stride_size_in_pages; + unsigned int search_area_stride_exponent; +}; + +/* DMA operations types */ +enum dma_ops_type { + DMA_FOR_COMMAND = 1, + DMA_FOR_READ_DATA, + DMA_FOR_WRITE_DATA, + DMA_FOR_READ_ECC_PAGE, + DMA_FOR_WRITE_ECC_PAGE +}; + +/** + * struct nand_timing - Fundamental timing attributes for NAND. + * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the + * maximum of tDS and tWP. A negative value + * indicates this characteristic isn't known. + * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the + * maximum of tDH, tWH and tREH. A negative value + * indicates this characteristic isn't known. + * @address_setup_in_ns: The address setup time, in nanoseconds. Usually + * the maximum of tCLS, tCS and tALS. A negative + * value indicates this characteristic isn't known. + * @gpmi_sample_delay_in_ns: A GPMI-specific timing parameter. A negative value + * indicates this characteristic isn't known. + * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + */ +struct nand_timing { + int8_t data_setup_in_ns; + int8_t data_hold_in_ns; + int8_t address_setup_in_ns; + int8_t gpmi_sample_delay_in_ns; + int8_t tREA_in_ns; + int8_t tRLOH_in_ns; + int8_t tRHOH_in_ns; +}; + +struct gpmi_nand_data { + /* System Interface */ + struct device *dev; + struct platform_device *pdev; + struct gpmi_nand_platform_data *pdata; + + /* Resources */ + struct resources resources; + + /* Flash Hardware */ + struct nand_timing timing; + + /* BCH */ + struct bch_geometry bch_geometry; + struct completion bch_done; + + /* NAND Boot issue */ + bool swap_block_mark; + struct boot_rom_geometry rom_geometry; + + /* MTD / NAND */ + struct nand_chip nand; + struct mtd_info mtd; + + /* General-use Variables */ + int current_chip; + unsigned int command_length; + + /* passed from upper layer */ + uint8_t *upper_buf; + int upper_len; + + /* for DMA operations */ + bool direct_dma_map_ok; + + struct scatterlist cmd_sgl; + char *cmd_buffer; + + struct scatterlist data_sgl; + char *data_buffer_dma; + + void *page_buffer_virt; + dma_addr_t page_buffer_phys; + unsigned int page_buffer_size; + + void *payload_virt; + dma_addr_t payload_phys; + + void *auxiliary_virt; + dma_addr_t auxiliary_phys; + + /* DMA channels */ +#define DMA_CHANS 8 + struct dma_chan *dma_chans[DMA_CHANS]; + struct mxs_dma_data dma_data; + enum dma_ops_type last_dma_type; + enum dma_ops_type dma_type; + struct completion dma_done; + + /* private */ + void *private; +}; + +/** + * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. + * @data_setup_in_cycles: The data setup time, in cycles. + * @data_hold_in_cycles: The data hold time, in cycles. + * @address_setup_in_cycles: The address setup time, in cycles. + * @use_half_periods: Indicates the clock is running slowly, so the + * NFC DLL should use half-periods. + * @sample_delay_factor: The sample delay factor. + */ +struct gpmi_nfc_hardware_timing { + uint8_t data_setup_in_cycles; + uint8_t data_hold_in_cycles; + uint8_t address_setup_in_cycles; + bool use_half_periods; + uint8_t sample_delay_factor; +}; + +/** + * struct timing_threshod - Timing threshold + * @max_data_setup_cycles: The maximum number of data setup cycles that + * can be expressed in the hardware. + * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires + * for data read internal setup. In the Reference + * Manual, see the chapter "High-Speed NAND + * Timing" for more details. + * @max_sample_delay_factor: The maximum sample delay factor that can be + * expressed in the hardware. + * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the + * sample delay DLL hardware can possibly work + * with (the DLL is unusable with longer periods). + * If the full-cycle period is greater than HALF + * this value, the DLL must be configured to use + * half-periods. + * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the + * DLL can implement. + * @clock_frequency_in_hz: The clock frequency, in Hz, during the current + * I/O transaction. If no I/O transaction is in + * progress, this is the clock frequency during + * the most recent I/O transaction. + */ +struct timing_threshod { + const unsigned int max_chip_count; + const unsigned int max_data_setup_cycles; + const unsigned int internal_data_setup_in_ns; + const unsigned int max_sample_delay_factor; + const unsigned int max_dll_clock_period_in_ns; + const unsigned int max_dll_delay_in_ns; + unsigned long clock_frequency_in_hz; + +}; + +/* Common Services */ +extern int common_nfc_set_geometry(struct gpmi_nand_data *); +extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *); +extern void prepare_data_dma(struct gpmi_nand_data *, + enum dma_data_direction dr); +extern int start_dma_without_bch_irq(struct gpmi_nand_data *, + struct dma_async_tx_descriptor *); +extern int start_dma_with_bch_irq(struct gpmi_nand_data *, + struct dma_async_tx_descriptor *); + +/* GPMI-NAND helper function library */ +extern int gpmi_init(struct gpmi_nand_data *); +extern void gpmi_clear_bch(struct gpmi_nand_data *); +extern void gpmi_dump_info(struct gpmi_nand_data *); +extern int bch_set_geometry(struct gpmi_nand_data *); +extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip); +extern int gpmi_send_command(struct gpmi_nand_data *); +extern void gpmi_begin(struct gpmi_nand_data *); +extern void gpmi_end(struct gpmi_nand_data *); +extern int gpmi_read_data(struct gpmi_nand_data *); +extern int gpmi_send_data(struct gpmi_nand_data *); +extern int gpmi_send_page(struct gpmi_nand_data *, + dma_addr_t payload, dma_addr_t auxiliary); +extern int gpmi_read_page(struct gpmi_nand_data *, + dma_addr_t payload, dma_addr_t auxiliary); + +/* BCH : Status Block Completion Codes */ +#define STATUS_GOOD 0x00 +#define STATUS_ERASED 0xff +#define STATUS_UNCORRECTABLE 0xfe + +/* Use the platform_id to distinguish different Archs. */ +#define IS_MX23 0x1 +#define IS_MX28 0x2 +#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) +#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) +#endif From 9ce244b3fb416ce6600e05612ac46b9692dcc638 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:37 -0700 Subject: [PATCH 0329/1596] mtd: support writing OOB without ECC This fixes issues with `nandwrite -n -o' and the MEMWRITEOOB[64] ioctls on hardware that writes ECC when writing OOB. The problem arises as follows: `nandwrite -n' can write page data to flash without applying ECC, but when used with the `-o' option, ECC is applied (incorrectly), contrary to the `--noecc' option. I found that this is the case because my hardware computes and writes ECC data to flash upon either OOB write or page write. Thus, to support a proper "no ECC" write, my driver must know when we're performing a raw OOB write vs. a normal ECC OOB write. However, MTD does not pass any raw mode information to the write_oob functions. This patch addresses the problems by: 1) Passing MTD_OOB_RAW down to lower layers, instead of just defaulting to MTD_OOB_PLACE 2) Handling MTD_OOB_RAW within the NAND layer's `nand_do_write_oob' 3) Adding a new (replaceable) function pointer in struct ecc_ctrl; this function should support writing OOB without ECC data. Current hardware often can use the same OOB write function when writing either with or without ECC This was tested with nandsim as well as on actual SLC NAND. Signed-off-by: Brian Norris Cc: Jim Quinlan Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 3 ++- drivers/mtd/nand/nand_base.c | 10 +++++++++- include/linux/mtd/nand.h | 3 +++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index b20625475132..bcb7f05fd27b 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -391,6 +391,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, uint64_t start, uint32_t length, void __user *ptr, uint32_t __user *retp) { + struct mtd_file_info *mfi = file->private_data; struct mtd_oob_ops ops; uint32_t retlen; int ret = 0; @@ -412,7 +413,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, ops.ooblen = length; ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OOB_RAW : MTD_OOB_PLACE; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7f2691f94322..b61a7c7bd097 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2404,7 +2404,11 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, chip->pagebuf = -1; nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); + + if (ops->mode == MTD_OOB_RAW) + status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); + else + status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); if (status) return status; @@ -3380,6 +3384,10 @@ int nand_scan_tail(struct mtd_info *mtd) BUG(); } + /* For many systems, the standard OOB write also works for raw */ + if (!chip->ecc.write_oob_raw) + chip->ecc.write_oob_raw = chip->ecc.write_oob; + /* * The number of bytes available for a client to place data into * the out of band area. diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 85fef68a379d..5f3fdd9877b7 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -340,6 +340,7 @@ struct nand_hw_control { * @read_subpage: function to read parts of the page covered by ECC. * @write_page: function to write a page according to the ECC generator * requirements. + * @write_oob_raw: function to write chip OOB data without ECC * @read_oob: function to read chip OOB data * @write_oob: function to write chip OOB data */ @@ -368,6 +369,8 @@ struct nand_ecc_ctrl { uint32_t offs, uint32_t len, uint8_t *buf); void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf); + int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, + int page); int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd); int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, From e9195edc59f33e9cabdd32a2959e927806670f45 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:43 -0700 Subject: [PATCH 0330/1596] mtd: nand: document nand_chip.oob_poi Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/linux/mtd/nand.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 5f3fdd9877b7..c7113a9cd66d 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -431,7 +431,8 @@ struct nand_buffers { * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring * data from array to read regs (tR). * @state: [INTERN] the current state of the NAND device - * @oob_poi: poison value buffer + * @oob_poi: "poison value buffer," used for laying out OOB data + * before writing * @page_shift: [INTERN] number of address bits in a page (column * address bits). * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock From c46f6483d21e93400e4a110de7902830173d53b0 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:38 -0700 Subject: [PATCH 0331/1596] mtd: support reading OOB without ECC This fixes issues with `nanddump -n' and the MEMREADOOB[64] ioctls on hardware that performs error correction when reading only OOB data. A driver for such hardware needs to know when we're doing a RAW vs. a normal write, but mtd_do_read_oob does not pass such information to the lower layers (e.g., NAND). We should pass MTD_OOB_RAW or MTD_OOB_PLACE based on the MTD file mode. For now, most drivers can get away with just setting: chip->ecc.read_oob_raw = chip->ecc.read_oob This is done by default; but for systems that behave as described above, you must supply your own replacement function. This was tested with nandsim as well as on actual SLC NAND. Signed-off-by: Brian Norris Cc: Jim Quinlan Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 14 ++++++++------ drivers/mtd/nand/nand_base.c | 7 ++++++- include/linux/mtd/nand.h | 3 +++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index bcb7f05fd27b..d0eaef67b9bb 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -435,9 +435,11 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, return ret; } -static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, - uint32_t length, void __user *ptr, uint32_t __user *retp) +static int mtd_do_readoob(struct file *file, struct mtd_info *mtd, + uint64_t start, uint32_t length, void __user *ptr, + uint32_t __user *retp) { + struct mtd_file_info *mfi = file->private_data; struct mtd_oob_ops ops; int ret = 0; @@ -455,7 +457,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, ops.ooblen = length; ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OOB_RAW : MTD_OOB_PLACE; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; @@ -716,7 +718,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, buf.length, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, buf.ptr, &buf_user->start); break; } @@ -743,7 +745,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, buf.length, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, (void __user *)(uintptr_t)buf.usr_ptr, &buf_user->length); break; @@ -1029,7 +1031,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd, if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, compat_ptr(buf.ptr), &buf_user->start); break; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index b61a7c7bd097..ad40607f5f24 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1787,7 +1787,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, page = realpage & chip->pagemask; while (1) { - sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); + if (ops->mode == MTD_OOB_RAW) + sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); + else + sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); len = min(len, readlen); buf = nand_transfer_oob(chip, buf, ops, len); @@ -3385,6 +3388,8 @@ int nand_scan_tail(struct mtd_info *mtd) } /* For many systems, the standard OOB write also works for raw */ + if (!chip->ecc.read_oob_raw) + chip->ecc.read_oob_raw = chip->ecc.read_oob; if (!chip->ecc.write_oob_raw) chip->ecc.write_oob_raw = chip->ecc.write_oob; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c7113a9cd66d..0b3d464cba13 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -341,6 +341,7 @@ struct nand_hw_control { * @write_page: function to write a page according to the ECC generator * requirements. * @write_oob_raw: function to write chip OOB data without ECC + * @read_oob_raw: function to read chip OOB data without ECC * @read_oob: function to read chip OOB data * @write_oob: function to write chip OOB data */ @@ -371,6 +372,8 @@ struct nand_ecc_ctrl { const uint8_t *buf); int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, int page); + int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd); int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd); int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, From 905c6bcdb42616da717a9bd6c0c5870dbd90b09e Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:39 -0700 Subject: [PATCH 0332/1596] mtd: move mtd_oob_mode_t to shared kernel/user space We will want to use the MTD_OOB_{PLACE,AUTO,RAW} modes in user-space applications through the introduction of new ioctls, so we should make this enum a shared type. This enum is now anonymous. Artem: tweaked the patch. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/onenand/onenand_base.c | 4 ++-- include/linux/mtd/mtd.h | 16 +--------------- include/mtd/mtd-abi.h | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index de98791f8101..493901a59e6e 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1351,7 +1351,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, struct mtd_ecc_stats stats; int read = 0, thislen, column, oobsize; size_t len = ops->ooblen; - mtd_oob_mode_t mode = ops->mode; + unsigned int mode = ops->mode; u_char *buf = ops->oobbuf; int ret = 0, readcmd; @@ -2074,7 +2074,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; size_t len = ops->ooblen; const u_char *buf = ops->oobbuf; - mtd_oob_mode_t mode = ops->mode; + unsigned int mode = ops->mode; to += ops->ooboffs; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index ff7bae08c5e0..6882cd968a3e 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -68,20 +68,6 @@ struct mtd_erase_region_info { unsigned long *lockmap; /* If keeping bitmap of locks */ }; -/* - * oob operation modes - * - * MTD_OOB_PLACE: oob data are placed at the given offset - * MTD_OOB_AUTO: oob data are automatically placed at the free areas - * which are defined by the ecclayout - * MTD_OOB_RAW: mode to read oob and data without doing ECC checking - */ -typedef enum { - MTD_OOB_PLACE, - MTD_OOB_AUTO, - MTD_OOB_RAW, -} mtd_oob_mode_t; - /** * struct mtd_oob_ops - oob operation operands * @mode: operation mode @@ -102,7 +88,7 @@ typedef enum { * OOB area. */ struct mtd_oob_ops { - mtd_oob_mode_t mode; + unsigned int mode; size_t len; size_t retlen; size_t ooblen; diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 3bdda5c426bd..af42c7a34805 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -45,6 +45,21 @@ struct mtd_oob_buf64 { __u64 usr_ptr; }; +/* + * oob operation modes + * + * MTD_OOB_PLACE: oob data are placed at the given offset (default) + * MTD_OOB_AUTO: oob data are automatically placed at the free areas + * which are defined by the internal ecclayout + * MTD_OOB_RAW: mode to read or write oob and data without doing ECC + * checking + */ +enum { + MTD_OOB_PLACE = 0, + MTD_OOB_AUTO = 1, + MTD_OOB_RAW = 2, +}; + #define MTD_ABSENT 0 #define MTD_RAM 1 #define MTD_ROM 2 From 0612b9ddc2eeda014dd805c87c752b342d8f80f0 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:40 -0700 Subject: [PATCH 0333/1596] mtd: rename MTD_OOB_* to MTD_OPS_* These modes are not necessarily for OOB only. Particularly, MTD_OOB_RAW affected operations on in-band page data as well. To clarify these options and to emphasize that their effect is applied per-operation, we change the primary prefix to MTD_OPS_. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/doc2000.c | 4 +-- drivers/mtd/devices/doc2001.c | 4 +-- drivers/mtd/devices/doc2001plus.c | 4 +-- drivers/mtd/inftlcore.c | 6 ++-- drivers/mtd/mtdchar.c | 10 ++++--- drivers/mtd/mtdpart.c | 2 +- drivers/mtd/mtdswap.c | 6 ++-- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 2 +- drivers/mtd/nand/nand_base.c | 40 +++++++++++++------------- drivers/mtd/nand/nand_bbt.c | 8 +++--- drivers/mtd/nand/sm_common.c | 2 +- drivers/mtd/nftlcore.c | 6 ++-- drivers/mtd/onenand/onenand_base.c | 38 ++++++++++++------------ drivers/mtd/onenand/onenand_bbt.c | 2 +- drivers/mtd/sm_ftl.c | 4 +-- drivers/mtd/ssfdc.c | 2 +- drivers/mtd/tests/mtd_oobtest.c | 24 ++++++++-------- drivers/mtd/tests/mtd_readtest.c | 2 +- drivers/staging/spectra/lld_mtd.c | 6 ++-- fs/jffs2/wbuf.c | 6 ++-- include/linux/mtd/mtd.h | 2 +- include/mtd/mtd-abi.h | 16 +++++------ 22 files changed, 99 insertions(+), 97 deletions(-) diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 8c9703309496..e9fad9151219 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -927,7 +927,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -1091,7 +1091,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, struct DiskOnChip *this = mtd->priv; int ret; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); mutex_lock(&this->lock); ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len, diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 3d2b459cea92..a3f7a27499be 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -631,7 +631,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -689,7 +689,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index d28c9d99979f..99351bc3e0ed 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -834,7 +834,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -919,7 +919,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 21aa981e42cd..652065e47a79 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -152,7 +152,7 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & (mtd->writesize - 1); ops.ooblen = len; ops.oobbuf = buf; @@ -172,7 +172,7 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & (mtd->writesize - 1); ops.ooblen = len; ops.oobbuf = buf; @@ -192,7 +192,7 @@ static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs; ops.ooblen = mtd->oobsize; ops.oobbuf = oob; diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d0eaef67b9bb..9b76438a3c27 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -221,7 +221,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.datbuf = kbuf; ops.oobbuf = NULL; ops.len = len; @@ -317,7 +317,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.datbuf = kbuf; ops.oobbuf = NULL; ops.ooboffs = 0; @@ -413,7 +413,8 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, ops.ooblen = length; ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OOB_RAW : MTD_OOB_PLACE; + ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OPS_RAW : + MTD_OPS_PLACE_OOB; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; @@ -457,7 +458,8 @@ static int mtd_do_readoob(struct file *file, struct mtd_info *mtd, ops.ooblen = length; ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OOB_RAW : MTD_OOB_PLACE; + ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OPS_RAW : + MTD_OPS_PLACE_OOB; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index c90b7ba362d7..cd7785aa1649 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -130,7 +130,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, if (ops->oobbuf) { size_t len, pages; - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) len = mtd->oobavail; else len = mtd->oobsize; diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 9961063b90a2..910309f260f8 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -350,7 +350,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) ops.oobbuf = d->oob_buf; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ret = mtdswap_read_oob(d, offset, &ops); @@ -389,7 +389,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, ops.ooboffs = 0; ops.oobbuf = (uint8_t *)&n; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = NULL; if (marker == MTDSWAP_TYPE_CLEAN) { @@ -931,7 +931,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = mtd->writesize; ops.ooblen = mtd->ecclayout->oobavail; ops.ooboffs = 0; diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 5c0fe0dd7057..071b63420f0e 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1104,7 +1104,7 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) * The BCH will use all the (page + oob). * Our gpmi_hw_ecclayout can only prohibit the JFFS2 to write the oob. * But it can not stop some ioctls such MEMWRITEOOB which uses - * MTD_OOB_PLACE. So We have to implement this function to prohibit + * MTD_OPS_PLACE_OOB. So We have to implement this function to prohibit * these ioctls too. */ return -EPERM; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ad40607f5f24..686b55770113 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1382,12 +1382,12 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, { switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: memcpy(oob, chip->oob_poi + ops->ooboffs, len); return oob + len; - case MTD_OOB_AUTO: { + case MTD_OPS_AUTO_OOB: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, roffs = ops->ooboffs; size_t bytes = 0; @@ -1437,7 +1437,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; - uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ? + uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; uint8_t *bufpoi, *oob, *buf; @@ -1469,7 +1469,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } /* Now read the page into the buffer */ - if (unlikely(ops->mode == MTD_OOB_RAW)) + if (unlikely(ops->mode == MTD_OPS_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page); else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) @@ -1759,7 +1759,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, stats = mtd->ecc_stats; - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; @@ -1787,7 +1787,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, page = realpage & chip->pagemask; while (1) { - if (ops->mode == MTD_OOB_RAW) + if (ops->mode == MTD_OPS_RAW) sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); else sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); @@ -1865,9 +1865,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, nand_get_device(chip, mtd, FL_READING); switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: break; default: @@ -2113,12 +2113,12 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: memcpy(chip->oob_poi + ops->ooboffs, oob, len); return oob + len; - case MTD_OOB_AUTO: { + case MTD_OPS_AUTO_OOB: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, woffs = ops->ooboffs; size_t bytes = 0; @@ -2167,7 +2167,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, uint32_t writelen = ops->len; uint32_t oobwritelen = ops->ooblen; - uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ? + uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; uint8_t *oob = ops->oobbuf; @@ -2236,7 +2236,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, } ret = chip->write_page(mtd, chip, wbuf, page, cached, - (ops->mode == MTD_OOB_RAW)); + (ops->mode == MTD_OPS_RAW)); if (ret) break; @@ -2356,7 +2356,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, (int)ops->ooblen); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; @@ -2408,7 +2408,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); - if (ops->mode == MTD_OOB_RAW) + if (ops->mode == MTD_OPS_RAW) status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); else status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); @@ -2445,9 +2445,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, nand_get_device(chip, mtd, FL_WRITING); switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: break; default: diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 6aa8125772b8..c488bcb84c90 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -302,7 +302,7 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; @@ -350,7 +350,7 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; ops.datbuf = buf; @@ -433,7 +433,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, ops.oobbuf = buf; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; for (j = 0; j < len; j++) { /* @@ -672,7 +672,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ops.ooblen = mtd->oobsize; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; if (!rcode) rcode = 0xff; diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index b6332e83b289..2c438ef53cf5 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c @@ -47,7 +47,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) /* As long as this function is called on erase block boundaries it will work correctly for 256 byte nand */ - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; ops.oobbuf = (void *)&oob; diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 93d6fc68b892..272e3c03e324 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -147,7 +147,7 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = len; ops.oobbuf = buf; @@ -168,7 +168,7 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = len; ops.oobbuf = buf; @@ -191,7 +191,7 @@ static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = mtd->oobsize; ops.oobbuf = oob; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 493901a59e6e..a52aa0f6b0c3 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1125,7 +1125,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, (int)len); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1170,7 +1170,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1229,7 +1229,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, (int)len); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1291,7 +1291,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1363,7 +1363,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, /* Initialize return length value */ ops->oobretlen = 0; - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1409,7 +1409,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, break; } - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, buf, column, thislen); else this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); @@ -1487,10 +1487,10 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, int ret; switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: break; - case MTD_OOB_RAW: + case MTD_OPS_RAW: /* Not implemented yet */ default: return -EINVAL; @@ -1908,7 +1908,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, if (!len) return 0; - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1945,7 +1945,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); else memcpy(oobbuf + oobcolumn, oob, thisooblen); @@ -2084,7 +2084,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, /* Initialize retlen, in case of early exit */ ops->oobretlen = 0; - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -2128,7 +2128,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen); else memcpy(oobbuf + column, buf, thislen); @@ -2217,10 +2217,10 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, int ret; switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: break; - case MTD_OOB_RAW: + case MTD_OPS_RAW: /* Not implemented yet */ default: return -EINVAL; @@ -2603,7 +2603,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) struct bbm_info *bbm = this->bbm; u_char buf[2] = {0, 0}; struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, + .mode = MTD_OPS_PLACE_OOB, .ooblen = 2, .oobbuf = buf, .ooboffs = 0, @@ -3171,7 +3171,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_RESET, 0, 0); this->wait(mtd, FL_RESETING); } else { - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooblen = len; ops.oobbuf = buf; ops.ooboffs = 0; @@ -3677,7 +3677,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int int i, ret; int block; struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, + .mode = MTD_OPS_PLACE_OOB, .ooboffs = 0, .ooblen = mtd->oobsize, .datbuf = NULL, diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 3b9a2a9573c6..09956c4fd850 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -80,7 +80,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr startblock = 0; from = 0; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooblen = readlen; ops.oobbuf = buf; ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 311a9e39a956..d927641cb0f5 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -256,7 +256,7 @@ static int sm_read_sector(struct sm_ftl *ftl, if (!oob) oob = &tmp_oob; - ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; + ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = SM_OOB_SIZE; ops.oobbuf = (void *)oob; @@ -336,7 +336,7 @@ static int sm_write_sector(struct sm_ftl *ftl, if (ftl->unstable) return -EIO; - ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; + ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB; ops.len = SM_SECTOR_SIZE; ops.datbuf = buffer; ops.ooboffs = 0; diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 5f917f0a9609..976e3d28b962 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -169,7 +169,7 @@ static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf) struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.ooboffs = 0; ops.ooblen = OOB_SIZE; ops.oobbuf = buf; diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c index dec92ae6111a..6bcff42296a9 100644 --- a/drivers/mtd/tests/mtd_oobtest.c +++ b/drivers/mtd/tests/mtd_oobtest.c @@ -131,7 +131,7 @@ static int write_eraseblock(int ebnum) for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { set_random_data(writebuf, use_len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; @@ -184,7 +184,7 @@ static int verify_eraseblock(int ebnum) for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { set_random_data(writebuf, use_len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; @@ -211,7 +211,7 @@ static int verify_eraseblock(int ebnum) if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { int k; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -276,7 +276,7 @@ static int verify_eraseblock_in_one_go(int ebnum) size_t len = mtd->ecclayout->oobavail * pgcnt; set_random_data(writebuf, len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = len; @@ -507,7 +507,7 @@ static int __init mtd_oobtest_init(void) addr0 += mtd->erasesize; /* Attempt to write off end of OOB */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; @@ -527,7 +527,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of OOB */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; @@ -551,7 +551,7 @@ static int __init mtd_oobtest_init(void) "block is bad\n"); else { /* Attempt to write off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; @@ -571,7 +571,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; @@ -595,7 +595,7 @@ static int __init mtd_oobtest_init(void) goto out; /* Attempt to write off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -615,7 +615,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -655,7 +655,7 @@ static int __init mtd_oobtest_init(void) addr = (i + 1) * mtd->erasesize - mtd->writesize; for (pg = 0; pg < cnt; ++pg) { set_random_data(writebuf, sz); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = sz; @@ -683,7 +683,7 @@ static int __init mtd_oobtest_init(void) continue; set_random_data(writebuf, mtd->ecclayout->oobavail * 2); addr = (i + 1) * mtd->erasesize - mtd->writesize; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail * 2; diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index 836792d1d60e..587e1e371c6c 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -66,7 +66,7 @@ static int read_eraseblock_by_page(int ebnum) if (mtd->oobsize) { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->oobsize; diff --git a/drivers/staging/spectra/lld_mtd.c b/drivers/staging/spectra/lld_mtd.c index 2bd34662beb5..a9c309a167c2 100644 --- a/drivers/staging/spectra/lld_mtd.c +++ b/drivers/staging/spectra/lld_mtd.c @@ -340,7 +340,7 @@ u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = read_data; ops.len = DeviceInfo.wPageDataSize; ops.oobbuf = read_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; @@ -400,7 +400,7 @@ u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = write_data; ops.len = DeviceInfo.wPageDataSize; ops.oobbuf = write_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; @@ -473,7 +473,7 @@ u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = NULL; ops.len = 0; ops.oobbuf = read_data; diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index a10fb24ca6e6..b09e51d2f81f 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -1025,7 +1025,7 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c, int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); struct mtd_oob_ops ops; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail; ops.oobbuf = c->oobbuf; ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -1068,7 +1068,7 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct mtd_oob_ops ops; int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.ooblen = cmlen; ops.oobbuf = c->oobbuf; ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -1094,7 +1094,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct mtd_oob_ops ops; int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.ooblen = cmlen; ops.oobbuf = (uint8_t *)&oob_cleanmarker; ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 6882cd968a3e..c2047b85691d 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -79,7 +79,7 @@ struct mtd_erase_region_info { * @ooblen: number of oob bytes to write/read * @oobretlen: number of oob bytes written/read * @ooboffs: offset of oob data in the oob area (only relevant when - * mode = MTD_OOB_PLACE) + * mode = MTD_OPS_PLACE_OOB) * @datbuf: data buffer - if NULL only oob data are read/written * @oobbuf: oob data buffer * diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index af42c7a34805..d30990e1858b 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -46,18 +46,18 @@ struct mtd_oob_buf64 { }; /* - * oob operation modes + * MTD operation modes * - * MTD_OOB_PLACE: oob data are placed at the given offset (default) - * MTD_OOB_AUTO: oob data are automatically placed at the free areas - * which are defined by the internal ecclayout - * MTD_OOB_RAW: mode to read or write oob and data without doing ECC + * MTD_OPS_PLACE_OOB: oob data are placed at the given offset (default) + * MTD_OPS_AUTO_OOB: oob data are automatically placed at the free areas + * which are defined by the internal ecclayout + * MTD_OPS_RAW: mode to read or write oob and data without doing ECC * checking */ enum { - MTD_OOB_PLACE = 0, - MTD_OOB_AUTO = 1, - MTD_OOB_RAW = 2, + MTD_OPS_PLACE_OOB = 0, + MTD_OPS_AUTO_OOB = 1, + MTD_OPS_RAW = 2, }; #define MTD_ABSENT 0 From beb133fc165e1289c858d8f952b982b7d0b313cd Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:41 -0700 Subject: [PATCH 0334/1596] mtd: rename MTD_MODE_* to MTD_FILE_MODE_* These modes hold their state only for the life of their file descriptor, and they overlap functionality with the MTD_OPS_* modes. Particularly, MTD_MODE_RAW and MTD_OPS_RAW cover the same function: to provide raw (i.e., without ECC) access to the flash. In fact, although it may not be clear, MTD_MODE_RAW implied that operations should enable the MTD_OPS_RAW mode. Thus, we should be specific on what each mode means. This is a start, where MTD_FILE_MODE_* actually represents a "file mode," not necessarily a true global MTD mode. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 36 ++++++++++++++++++------------------ include/mtd/mtd-abi.h | 8 ++++---- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 9b76438a3c27..4004f2b2f403 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -211,13 +211,13 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t len = min_t(size_t, count, size); switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: { struct mtd_oob_ops ops; @@ -302,10 +302,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count } switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: ret = -EROFS; break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: if (!mtd->write_user_prot_reg) { ret = -EOPNOTSUPP; break; @@ -313,7 +313,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: { struct mtd_oob_ops ops; @@ -368,13 +368,13 @@ static int otp_select_filemode(struct mtd_file_info *mfi, int mode) if (!mtd->read_fact_prot_reg) ret = -EOPNOTSUPP; else - mfi->mode = MTD_MODE_OTP_FACTORY; + mfi->mode = MTD_FILE_MODE_OTP_FACTORY; break; case MTD_OTP_USER: if (!mtd->read_fact_prot_reg) ret = -EOPNOTSUPP; else - mfi->mode = MTD_MODE_OTP_USER; + mfi->mode = MTD_FILE_MODE_OTP_USER; break; default: ret = -EINVAL; @@ -413,7 +413,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, ops.ooblen = length; ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OPS_RAW : + ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) @@ -458,7 +458,7 @@ static int mtd_do_readoob(struct file *file, struct mtd_info *mtd, ops.ooblen = length; ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = (mfi->mode == MTD_MODE_RAW) ? MTD_OPS_RAW : + ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) @@ -849,7 +849,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&mode, argp, sizeof(int))) return -EFAULT; - mfi->mode = MTD_MODE_NORMAL; + mfi->mode = MTD_FILE_MODE_NORMAL; ret = otp_select_filemode(mfi, mode); @@ -865,11 +865,11 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) return -ENOMEM; ret = -EOPNOTSUPP; switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: if (mtd->get_fact_prot_info) ret = mtd->get_fact_prot_info(mtd, buf, 4096); break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: if (mtd->get_user_prot_info) ret = mtd->get_user_prot_info(mtd, buf, 4096); break; @@ -893,7 +893,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) { struct otp_info oinfo; - if (mfi->mode != MTD_MODE_OTP_USER) + if (mfi->mode != MTD_FILE_MODE_OTP_USER) return -EINVAL; if (copy_from_user(&oinfo, argp, sizeof(oinfo))) return -EFAULT; @@ -937,17 +937,17 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) mfi->mode = 0; switch(arg) { - case MTD_MODE_OTP_FACTORY: - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_USER: ret = otp_select_filemode(mfi, arg); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: if (!mtd->read_oob || !mtd->write_oob) return -EOPNOTSUPP; mfi->mode = arg; - case MTD_MODE_NORMAL: + case MTD_FILE_MODE_NORMAL: break; default: ret = -EINVAL; diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index d30990e1858b..1885aa98b311 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -200,10 +200,10 @@ struct mtd_ecc_stats { * Read/write file modes for access to MTD */ enum mtd_file_modes { - MTD_MODE_NORMAL = MTD_OTP_OFF, - MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY, - MTD_MODE_OTP_USER = MTD_OTP_USER, - MTD_MODE_RAW, + MTD_FILE_MODE_NORMAL = MTD_OTP_OFF, + MTD_FILE_MODE_OTP_FACTORY = MTD_OTP_FACTORY, + MTD_FILE_MODE_OTP_USER = MTD_OTP_USER, + MTD_FILE_MODE_RAW, }; #endif /* __MTD_ABI_H__ */ From e99d8b089a6c6fd72f022168e3bf8f22d4e5e137 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 9 Sep 2011 09:59:03 -0700 Subject: [PATCH 0335/1596] mtd: add MEMWRITE ioctl Implement a new ioctl for writing both page data and OOB to flash at the same time. This ioctl is intended to be a generic interface that can replace other ioctls (MEMWRITEOOB and MEMWRITEOOB64) and cover the functionality of several other old ones, e.g., MEMWRITE can: * write autoplaced OOB instead of using ECCGETLAYOUT (deprecated) and working around the reserved areas * write raw (no ECC) OOB instead of using MTDFILEMODE to set the per-file-descriptor MTD_FILE_MODE_RAW * write raw (no ECC) data instead of using MTDFILEMODE (MTD_FILE_MODE_RAW) and using standard character device "write" This ioctl is especially useful for MLC NAND, which cannot be written twice (i.e., we cannot successfully write the page data and OOB in two separate operations). Instead, MEMWRITE can write both in a single operation. Note that this ioctl is not affected by the MTD file mode (i.e., MTD_FILE_MODE_RAW vs. MTD_FILE_MODE_NORMAL), since it receives its write mode as an input parameter. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 56 +++++++++++++++++++++++++++++++++++++++++++ include/mtd/mtd-abi.h | 11 +++++++++ 2 files changed, 67 insertions(+) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 4004f2b2f403..1547e2a68279 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -566,6 +566,55 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, } } +static int mtd_write_ioctl(struct mtd_info *mtd, + struct mtd_write_req __user *argp) +{ + struct mtd_write_req req; + struct mtd_oob_ops ops; + void __user *usr_data, *usr_oob; + int ret; + + if (copy_from_user(&req, argp, sizeof(req)) || + !access_ok(VERIFY_READ, req.usr_data, req.len) || + !access_ok(VERIFY_READ, req.usr_oob, req.ooblen)) + return -EFAULT; + if (!mtd->write_oob) + return -EOPNOTSUPP; + + ops.mode = req.mode; + ops.len = (size_t)req.len; + ops.ooblen = (size_t)req.ooblen; + ops.ooboffs = 0; + + usr_data = (void __user *)(uintptr_t)req.usr_data; + usr_oob = (void __user *)(uintptr_t)req.usr_oob; + + if (req.usr_data) { + ops.datbuf = memdup_user(usr_data, ops.len); + if (IS_ERR(ops.datbuf)) + return PTR_ERR(ops.datbuf); + } else { + ops.datbuf = NULL; + } + + if (req.usr_oob) { + ops.oobbuf = memdup_user(usr_oob, ops.ooblen); + if (IS_ERR(ops.oobbuf)) { + kfree(ops.datbuf); + return PTR_ERR(ops.oobbuf); + } + } else { + ops.oobbuf = NULL; + } + + ret = mtd->write_oob(mtd, (loff_t)req.start, &ops); + + kfree(ops.datbuf); + kfree(ops.oobbuf); + + return ret; +} + static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) { struct mtd_file_info *mfi = file->private_data; @@ -753,6 +802,13 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) break; } + case MEMWRITE: + { + ret = mtd_write_ioctl(mtd, + (struct mtd_write_req __user *)arg); + break; + } + case MEMLOCK: { struct erase_info_user einfo; diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 1885aa98b311..1a16046b1d97 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -60,6 +60,16 @@ enum { MTD_OPS_RAW = 2, }; +struct mtd_write_req { + __u64 start; + __u64 len; + __u64 ooblen; + __u64 usr_data; + __u64 usr_oob; + __u8 mode; + __u8 padding[7]; +}; + #define MTD_ABSENT 0 #define MTD_RAM 1 #define MTD_ROM 2 @@ -147,6 +157,7 @@ struct otp_info { #define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64) #define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64) #define MEMISLOCKED _IOR('M', 23, struct erase_info_user) +#define MEMWRITE _IOWR('M', 24, struct mtd_write_req) /* * Obsolete legacy interface. Keep it in order not to break userspace From 4180f24a7bff3aa7978e3785d0edd5dcc4af9049 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:44 -0700 Subject: [PATCH 0336/1596] mtd: document ABI We're missing a lot of important documentation in include/mtd/mtd-abi.h: * add a simple description of each ioctl (feel free to expand!) * give full explanations of recently added and modified operations * explain the usage of "RAW" that appear in different modes and types of operations * fix some comment style along the way Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/linux/mtd/mtd.h | 2 +- include/mtd/mtd-abi.h | 86 ++++++++++++++++++++++++++++++++++------- 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index c2047b85691d..37d082793f62 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -79,7 +79,7 @@ struct mtd_erase_region_info { * @ooblen: number of oob bytes to write/read * @oobretlen: number of oob bytes written/read * @ooboffs: offset of oob data in the oob area (only relevant when - * mode = MTD_OPS_PLACE_OOB) + * mode = MTD_OPS_PLACE_OOB or MTD_OPS_RAW) * @datbuf: data buffer - if NULL only oob data are read/written * @oobbuf: oob data buffer * diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 1a16046b1d97..7dee9709fbfc 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -45,14 +45,18 @@ struct mtd_oob_buf64 { __u64 usr_ptr; }; -/* +/** * MTD operation modes * - * MTD_OPS_PLACE_OOB: oob data are placed at the given offset (default) - * MTD_OPS_AUTO_OOB: oob data are automatically placed at the free areas + * @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default) + * @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas * which are defined by the internal ecclayout - * MTD_OPS_RAW: mode to read or write oob and data without doing ECC - * checking + * @MTD_OPS_RAW: data are transferred as-is, with no error correction; + * this mode implies %MTD_OPS_PLACE_OOB + * + * These modes can be passed to ioctl(MEMWRITE) and are also used internally. + * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs. + * %MTD_FILE_MODE_RAW. */ enum { MTD_OPS_PLACE_OOB = 0, @@ -60,6 +64,22 @@ enum { MTD_OPS_RAW = 2, }; +/** + * struct mtd_write_req - data structure for requesting a write operation + * + * @start: start address + * @len: length of data buffer + * @ooblen: length of OOB buffer + * @usr_data: user-provided data buffer + * @usr_oob: user-provided OOB buffer + * @mode: MTD mode (see "MTD operation modes") + * @padding: reserved, must be set to 0 + * + * This structure supports ioctl(MEMWRITE) operations, allowing data and/or OOB + * writes in various modes. To write to OOB-only, set @usr_data == NULL, and to + * write data-only, set @usr_oob == NULL. However, setting both @usr_data and + * @usr_oob to NULL is not allowed. + */ struct mtd_write_req { __u64 start; __u64 len; @@ -84,13 +104,13 @@ struct mtd_write_req { #define MTD_NO_ERASE 0x1000 /* No erase necessary */ #define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */ -// Some common devices / combinations of capabilities +/* Some common devices / combinations of capabilities */ #define MTD_CAP_ROM 0 #define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE) #define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE) #define MTD_CAP_NANDFLASH (MTD_WRITEABLE) -/* ECC byte placement */ +/* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */ #define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended) #define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode) #define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme @@ -105,10 +125,10 @@ struct mtd_write_req { struct mtd_info_user { __u8 type; __u32 flags; - __u32 size; // Total size of the MTD + __u32 size; /* Total size of the MTD */ __u32 erasesize; __u32 writesize; - __u32 oobsize; // Amount of OOB data per block (e.g. 16) + __u32 oobsize; /* Amount of OOB data per block (e.g. 16) */ /* The below two fields are obsolete and broken, do not use them * (TODO: remove at some point) */ __u32 ecctype; @@ -117,9 +137,9 @@ struct mtd_info_user { struct region_info_user { __u32 offset; /* At which this region starts, - * from the beginning of the MTD */ - __u32 erasesize; /* For this region */ - __u32 numblocks; /* Number of blocks in this region */ + * from the beginning of the MTD */ + __u32 erasesize; /* For this region */ + __u32 numblocks; /* Number of blocks in this region */ __u32 regionindex; }; @@ -135,28 +155,54 @@ struct otp_info { * Try to avoid adding a new ioctl with the same ioctl number. */ +/* Get basic MTD characteristics info (better to use sysfs) */ #define MEMGETINFO _IOR('M', 1, struct mtd_info_user) +/* Erase segment of MTD */ #define MEMERASE _IOW('M', 2, struct erase_info_user) +/* Write out-of-band data from MTD */ #define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) +/* Read out-of-band data from MTD */ #define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf) +/* Lock a chip (for MTD that supports it) */ #define MEMLOCK _IOW('M', 5, struct erase_info_user) +/* Unlock a chip (for MTD that supports it) */ #define MEMUNLOCK _IOW('M', 6, struct erase_info_user) +/* Get the number of different erase regions */ #define MEMGETREGIONCOUNT _IOR('M', 7, int) +/* Get information about the erase region for a specific index */ #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) +/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */ #define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) +/* Check if an eraseblock is bad */ #define MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t) +/* Mark an eraseblock as bad */ #define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t) +/* Set OTP (One-Time Programmable) mode (factory vs. user) */ #define OTPSELECT _IOR('M', 13, int) +/* Get number of OTP (One-Time Programmable) regions */ #define OTPGETREGIONCOUNT _IOW('M', 14, int) +/* Get all OTP (One-Time Programmable) info about MTD */ #define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) +/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */ #define OTPLOCK _IOR('M', 16, struct otp_info) +/* Get ECC layout (deprecated) */ #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout_user) +/* Get statistics about corrected/uncorrected errors */ #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) +/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */ #define MTDFILEMODE _IO('M', 19) +/* Erase segment of MTD (supports 64-bit address) */ #define MEMERASE64 _IOW('M', 20, struct erase_info_user64) +/* Write data to OOB (64-bit version) */ #define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64) +/* Read data from OOB (64-bit version) */ #define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64) +/* Check if chip is locked (for MTD that supports it) */ #define MEMISLOCKED _IOR('M', 23, struct erase_info_user) +/* + * Most generic write interface; can write in-band and/or out-of-band in various + * modes (see "struct mtd_write_req") + */ #define MEMWRITE _IOWR('M', 24, struct mtd_write_req) /* @@ -208,7 +254,21 @@ struct mtd_ecc_stats { }; /* - * Read/write file modes for access to MTD + * MTD file modes - for read/write access to MTD + * + * @MTD_FILE_MODE_NORMAL: OTP disabled, ECC enabled + * @MTD_FILE_MODE_OTP_FACTORY: OTP enabled in factory mode + * @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode + * @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled + * + * These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained + * separately for each open file descriptor. + * + * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - + * raw access to the flash, without error correction or autoplacement schemes. + * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode + * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is + * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)). */ enum mtd_file_modes { MTD_FILE_MODE_NORMAL = MTD_OTP_OFF, From 4a89ff885ff9f64ea62669100766e10e4e257c6e Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:45 -0700 Subject: [PATCH 0337/1596] mtd: nand: kill member `ops' of `struct nand_chip' The nand_chip.ops field is a struct that is passed around globally with no particular reason. Every time it is used, it could just as easily be replaced with a local struct that is updated on each operation. So make it local. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 46 ++++++++++++++++++++---------------- include/linux/mtd/nand.h | 3 --- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 686b55770113..c9767b511dfe 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -406,6 +406,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) if (chip->bbt_options & NAND_BBT_USE_FLASH) ret = nand_update_bbt(mtd, ofs); else { + struct mtd_oob_ops ops; + nand_get_device(chip, mtd, FL_WRITING); /* @@ -414,13 +416,12 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) * procedure. We write two bytes per location, so we dont have * to mess with 16 bit access. */ + ops.len = ops.ooblen = 2; + ops.datbuf = NULL; + ops.oobbuf = buf; + ops.ooboffs = chip->badblockpos & ~0x01; do { - chip->ops.len = chip->ops.ooblen = 2; - chip->ops.datbuf = NULL; - chip->ops.oobbuf = buf; - chip->ops.ooboffs = chip->badblockpos & ~0x01; - - ret = nand_do_write_oob(mtd, ofs, &chip->ops); + ret = nand_do_write_oob(mtd, ofs, &ops); i++; ofs += mtd->writesize; @@ -1573,6 +1574,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -1583,13 +1585,13 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, nand_get_device(chip, mtd, FL_READING); - chip->ops.len = len; - chip->ops.datbuf = buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = buf; + ops.oobbuf = NULL; - ret = nand_do_read_ops(mtd, from, &chip->ops); + ret = nand_do_read_ops(mtd, from, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; nand_release_device(mtd); @@ -2278,6 +2280,7 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -2292,13 +2295,13 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); - chip->ops.len = len; - chip->ops.datbuf = (uint8_t *)buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = (uint8_t *)buf; + ops.oobbuf = NULL; - ret = nand_do_write_ops(mtd, to, &chip->ops); + ret = nand_do_write_ops(mtd, to, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; return ret; } @@ -2316,6 +2319,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -2326,13 +2330,13 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, nand_get_device(chip, mtd, FL_WRITING); - chip->ops.len = len; - chip->ops.datbuf = (uint8_t *)buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = (uint8_t *)buf; + ops.oobbuf = NULL; - ret = nand_do_write_ops(mtd, to, &chip->ops); + ret = nand_do_write_ops(mtd, to, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; nand_release_device(mtd); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 0b3d464cba13..904131bab501 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -427,7 +427,6 @@ struct nand_buffers { * @ecc: [BOARDSPECIFIC] ECC control structure * @buffers: buffer structure for read/write * @hwcontrol: platform-specific hardware control structure - * @ops: oob operation operands * @erase_cmd: [INTERN] erase command write function, selectable due * to AND support. * @scan_bbt: [REPLACEABLE] function to scan bad block table @@ -535,8 +534,6 @@ struct nand_chip { struct nand_buffers *buffers; struct nand_hw_control hwcontrol; - struct mtd_oob_ops ops; - uint8_t *bbt; struct nand_bbt_descr *bbt_td; struct nand_bbt_descr *bbt_md; From 19fb4341ad7a72e4c996234a1834e52e1f7954ba Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 30 Aug 2011 18:45:46 -0700 Subject: [PATCH 0338/1596] mtd: kill old field for `struct mtd_info_user' The ecctype and eccsize fields have been obsolete for a while. Since they don't have any users, we can kill them and leave padding in their place for now. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdchar.c | 4 ++-- include/mtd/mtd-abi.h | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 1547e2a68279..8feb5fdcd97b 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -672,8 +672,8 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) info.erasesize = mtd->erasesize; info.writesize = mtd->writesize; info.oobsize = mtd->oobsize; - /* The below fields are obsolete */ - info.ecctype = -1; + /* The below field is obsolete */ + info.padding = 0; if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) return -EFAULT; break; diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 7dee9709fbfc..1a7e1d20adf9 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -129,10 +129,7 @@ struct mtd_info_user { __u32 erasesize; __u32 writesize; __u32 oobsize; /* Amount of OOB data per block (e.g. 16) */ - /* The below two fields are obsolete and broken, do not use them - * (TODO: remove at some point) */ - __u32 ecctype; - __u32 eccsize; + __u64 padding; /* Old obsolete field; do not use */ }; struct region_info_user { From 3e2b82b9073e8bf0b4f359fa3045e81d9fe87f7d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 7 Sep 2011 09:50:29 +0200 Subject: [PATCH 0339/1596] mtd: drop Integrator flash map Kconfig The integrator flash has been deleted, even from the Makefile. Drop the Kconfig entry as well. Signed-off-by: Linus Walleij Acked-by: Marc Zyngier Signed-off-by: Artem Bityutskiy --- drivers/mtd/maps/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 1b0d56cf4c47..8e0c4bf9f7fb 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -332,10 +332,6 @@ config MTD_SOLUTIONENGINE This enables access to the flash chips on the Hitachi SolutionEngine and similar boards. Say 'Y' if you are building a kernel for such a board. -config MTD_ARM_INTEGRATOR - tristate "CFI Flash device mapped on ARM Integrator/P720T" - depends on ARM && MTD_CFI - config MTD_CDB89712 tristate "Cirrus CDB89712 evaluation board mappings" depends on MTD_CFI && ARCH_CDB89712 From 105513cc4a25522f959788371bd612f987d4d184 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Sep 2011 13:13:28 -0700 Subject: [PATCH 0340/1596] mtd: nand: refactor scanning code A few pieces of code are unnecessarily duplicated. For easier maintenance, we should fix this. This should have no functional effect. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index c488bcb84c90..cbf9b695c6f2 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -306,28 +306,16 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, ops.ooboffs = 0; ops.ooblen = mtd->oobsize; - while (len > 0) { - if (len <= mtd->writesize) { - ops.oobbuf = buf + len; - ops.datbuf = buf; - ops.len = len; - res = mtd->read_oob(mtd, offs, &ops); - - /* Ignore ECC errors when checking for BBM */ - if (res != -EUCLEAN && res != -EBADMSG) - return res; - return 0; - } else { - ops.oobbuf = buf + mtd->writesize; - ops.datbuf = buf; - ops.len = mtd->writesize; - res = mtd->read_oob(mtd, offs, &ops); + ops.datbuf = buf; + ops.len = min(len, (size_t)mtd->writesize); + ops.oobbuf = buf + ops.len; - /* Ignore ECC errors when checking for BBM */ - if (res && res != -EUCLEAN && res != -EBADMSG) - return res; - } + res = mtd->read_oob(mtd, offs, &ops); + + /* Ignore ECC errors when checking for BBM */ + if (res && res != -EUCLEAN && res != -EBADMSG) + return res; buf += mtd->oobsize + mtd->writesize; len -= mtd->writesize; From afa17de262633603dd65f89e9370f48e56b8c557 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Sep 2011 13:13:29 -0700 Subject: [PATCH 0341/1596] mtd: nand: do not ignore all ECC errors There are a few reasons not to ignore ECC errors here. First, mtd->read_oob is being called in raw mode, so there should be no error correction in the first place. Second, if we change this such that there *is* error correction in this function, then we will want to pass the error message upward. In fact, the code I introduced to "ignore ECC errors" would have been better if it had just placed this test down in `scan_block_full()' in the first place. We would like to ignore ECC errors when we are simply checking for bad block markers (e.g., factory marked), but we may not want to ignore ECC errors when scanning OOB for a flash-based BBT pattern (in `scan_read_raw()'; note that the return codes from `scan_read_raw()' are not actually handled yet). Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index cbf9b695c6f2..fcfaf06beaaf 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -313,8 +313,7 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, res = mtd->read_oob(mtd, offs, &ops); - /* Ignore ECC errors when checking for BBM */ - if (res && res != -EUCLEAN && res != -EBADMSG) + if (res) return res; buf += mtd->oobsize + mtd->writesize; @@ -400,7 +399,8 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, int ret, j; ret = scan_read_raw_oob(mtd, buf, offs, readlen); - if (ret) + /* Ignore ECC errors when checking for BBM */ + if (ret && ret != -EUCLEAN && ret != -EBADMSG) return ret; for (j = 0; j < len; j++, buf += scanlen) { From 1196ac5a9969f180c67e9a4454384250ab034452 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Sep 2011 13:13:32 -0700 Subject: [PATCH 0342/1596] mtd: nand: remove unnecessary variable `writeops' is unnecessary in the function `nand_update_bbt()' Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index fcfaf06beaaf..c1074ac9bdac 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1171,7 +1171,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) int nand_update_bbt(struct mtd_info *mtd, loff_t offs) { struct nand_chip *this = mtd->priv; - int len, res = 0, writeops = 0; + int len, res = 0; int chip, chipsel; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; @@ -1187,8 +1187,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) if (!buf) return -ENOMEM; - writeops = md != NULL ? 0x03 : 0x01; - /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chip = (int)(offs >> this->chip_shift); @@ -1203,13 +1201,13 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) md->version[chip]++; /* Write the bad block table to the device? */ - if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { + if (td->options & NAND_BBT_WRITE) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) goto out; } /* Write the mirror bad block table to the device? */ - if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { + if (md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); } From 596d74527a804418d88e1178c9d72aff5649e89c Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Sep 2011 13:13:33 -0700 Subject: [PATCH 0343/1596] mtd: nand: fix style Remove some extra spaces Consistently use '0x' prefix for bitfield-like constants Spelling: "aplies" -> "applies" Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index c1074ac9bdac..e962167c9b71 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -183,16 +183,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, size_t retlen, len, totlen; loff_t from; int bits = td->options & NAND_BBT_NRBITS_MSK; - uint8_t msk = (uint8_t) ((1 << bits) - 1); + uint8_t msk = (uint8_t)((1 << bits) - 1); u32 marker_len; int reserved_block_code = td->reserved_block_code; totlen = (num * bits) >> 3; marker_len = add_marker_len(td); - from = ((loff_t) page) << this->page_shift; + from = ((loff_t)page) << this->page_shift; while (totlen) { - len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); if (marker_len) { /* * In case the BBT marker is not in the OOB area it @@ -250,7 +250,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, * @mtd: MTD device structure * @buf: temporary buffer * @td: descriptor for the bad block table - * @chip: read the table for a specific chip, -1 read all chips; aplies only if + * @chip: read the table for a specific chip, -1 read all chips; applies only if * NAND_BBT_PERCHIP option is set * * Read the bad block table for all chips starting at a given page. We assume @@ -743,12 +743,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, bbtoffs = chip * (numblocks >> 2); - to = ((loff_t) page) << this->page_shift; + to = ((loff_t)page) << this->page_shift; /* Must we save the block contents? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ - to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); + to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); len = 1 << this->bbt_erase_shift; res = mtd->read(mtd, to, len, &retlen, buf); if (res < 0) { @@ -771,7 +771,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, pageoffs = page - (int)(to >> this->page_shift); offs = pageoffs << this->page_shift; /* Preset the bbt area with 0xff */ - memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); + memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); } else if (td->options & NAND_BBT_NO_OOB) { @@ -781,7 +781,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (td->options & NAND_BBT_VERSION) offs++; /* Calc length */ - len = (size_t) (numblocks >> sft); + len = (size_t)(numblocks >> sft); len += offs; /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); @@ -791,7 +791,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memcpy(buf, td->pattern, td->len); } else { /* Calc length */ - len = (size_t) (numblocks >> sft); + len = (size_t)(numblocks >> sft); /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ @@ -903,14 +903,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (td->pages[i] == -1) { rd = md; td->version[i] = md->version[i]; - writeops = 1; + writeops = 0x01; goto writecheck; } if (md->pages[i] == -1) { rd = td; md->version[i] = td->version[i]; - writeops = 2; + writeops = 0x02; goto writecheck; } @@ -921,14 +921,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc goto writecheck; } - if (((int8_t) (td->version[i] - md->version[i])) > 0) { + if (((int8_t)(td->version[i] - md->version[i])) > 0) { rd = td; md->version[i] = td->version[i]; - writeops = 2; + writeops = 0x02; } else { rd = md; td->version[i] = md->version[i]; - writeops = 1; + writeops = 0x01; } goto writecheck; From c5e8ef9c21a492f1e0436b350bbc3e916f93e506 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Sep 2011 13:13:34 -0700 Subject: [PATCH 0344/1596] mtd: nand: begin restructuring check_create We will begin restructuring the code for check_create so that we can make some important changes. For now, we should just begin to get rid of some goto statements to make things cleaner. This is the first step of a few, which are separated to make them easier to follow. This step should just be a code refactor. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index e962167c9b71..42b523a84fc6 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -898,30 +898,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (td->pages[i] == -1 && md->pages[i] == -1) { writeops = 0x03; goto create; - } - - if (td->pages[i] == -1) { + } else if (td->pages[i] == -1) { rd = md; td->version[i] = md->version[i]; writeops = 0x01; - goto writecheck; - } - - if (md->pages[i] == -1) { + } else if (md->pages[i] == -1) { rd = td; md->version[i] = td->version[i]; writeops = 0x02; - goto writecheck; - } - - if (td->version[i] == md->version[i]) { + } else if (td->version[i] == md->version[i]) { rd = td; if (!(td->options & NAND_BBT_VERSION)) rd2 = md; - goto writecheck; - } - - if (((int8_t)(td->version[i] - md->version[i])) > 0) { + } else if (((int8_t)(td->version[i] - md->version[i])) > 0) { rd = td; md->version[i] = td->version[i]; writeops = 0x02; @@ -930,17 +919,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc td->version[i] = md->version[i]; writeops = 0x01; } - - goto writecheck; - } else { if (td->pages[i] == -1) { writeops = 0x01; goto create; } rd = td; - goto writecheck; } + goto writecheck; create: /* Create the bad block table by scanning the device? */ if (!(td->options & NAND_BBT_CREATE)) From b61bf5bbf619fc66ca866a27038da0b91cafb92d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Sep 2011 13:13:35 -0700 Subject: [PATCH 0345/1596] mtd: nand: remove gotos in `check_create()' This is a second step in restructuring `check_create()'. When we don't rely on goto statements for our main functionality, the code will become a little easier to manipulate. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 42b523a84fc6..7dbfce4a1a5b 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -875,7 +875,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b */ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) { - int i, chips, writeops, chipsel, res; + int i, chips, writeops, create, chipsel, res; struct nand_chip *this = mtd->priv; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; @@ -889,6 +889,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc for (i = 0; i < chips; i++) { writeops = 0; + create = 0; rd = NULL; rd2 = NULL; /* Per chip or per device? */ @@ -896,8 +897,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /* Mirrored table available? */ if (md) { if (td->pages[i] == -1 && md->pages[i] == -1) { + create = 1; writeops = 0x03; - goto create; } else if (td->pages[i] == -1) { rd = md; td->version[i] = md->version[i]; @@ -921,25 +922,27 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } } else { if (td->pages[i] == -1) { + create = 1; writeops = 0x01; - goto create; + } else { + rd = td; } - rd = td; } - goto writecheck; - create: - /* Create the bad block table by scanning the device? */ - if (!(td->options & NAND_BBT_CREATE)) - continue; - /* Create the table in memory by scanning the chip(s) */ - if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) - create_bbt(mtd, buf, bd, chipsel); + if (create) { + /* Create the bad block table by scanning the device? */ + if (!(td->options & NAND_BBT_CREATE)) + continue; + + /* Create the table in memory by scanning the chip(s) */ + if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) + create_bbt(mtd, buf, bd, chipsel); + + td->version[i] = 1; + if (md) + md->version[i] = 1; + } - td->version[i] = 1; - if (md) - md->version[i] = 1; - writecheck: /* Read back first? */ if (rd) read_abs_bbt(mtd, buf, rd, chipsel); From 484fc254b88257a2d8b3759aa062e8e8b35e0988 Mon Sep 17 00:00:00 2001 From: Wang Sheng-Hui Date: Thu, 8 Sep 2011 12:32:14 +0200 Subject: [PATCH 0346/1596] elevator: use ELV_NAME_MAX instead of magic number 16 for chosen_elevator We have ELV_NAME_MAX defined to 16, and hence we should use it instead of the magic nubmer 16 for elevator's name string. Signed-off-by: Wang Sheng-Hui Signed-off-by: Jens Axboe --- block/elevator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/elevator.c b/block/elevator.c index a3b64bc71d88..cb332cb7ac6b 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -182,7 +182,7 @@ static void elevator_attach(struct request_queue *q, struct elevator_queue *eq, eq->elevator_data = data; } -static char chosen_elevator[16]; +static char chosen_elevator[ELV_NAME_MAX]; static int __init elevator_setup(char *str) { From 166e1f901b01872e8b70733a3f2e2c6980389cf8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 12 Sep 2011 12:08:27 +0200 Subject: [PATCH 0347/1596] block: export __make_request Avoid the hacks need for request based device mappers currently by simply exporting the symbol instead of trying to get it through the back door. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- block/blk-core.c | 5 ++--- drivers/md/dm.c | 13 +------------ include/linux/blkdev.h | 2 ++ 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index b627558c461f..56ef387e7d27 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -38,8 +38,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete); -static int __make_request(struct request_queue *q, struct bio *bio); - /* * For the allocated request tables */ @@ -1213,7 +1211,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) blk_rq_bio_prep(req->q, req, bio); } -static int __make_request(struct request_queue *q, struct bio *bio) +int __make_request(struct request_queue *q, struct bio *bio) { const bool sync = !!(bio->bi_rw & REQ_SYNC); struct blk_plug *plug; @@ -1317,6 +1315,7 @@ static int __make_request(struct request_queue *q, struct bio *bio) out: return 0; } +EXPORT_SYMBOL_GPL(__make_request); /* for device mapper only */ /* * If bio->bi_dev is a partition, remap the location diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 52b39f335bb3..d8d7b8d9dd28 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -180,9 +180,6 @@ struct mapped_device { /* forced geometry settings */ struct hd_geometry geometry; - /* For saving the address of __make_request for request based dm */ - make_request_fn *saved_make_request_fn; - /* sysfs handle */ struct kobject kobj; @@ -1420,13 +1417,6 @@ static int _dm_request(struct request_queue *q, struct bio *bio) return 0; } -static int dm_make_request(struct request_queue *q, struct bio *bio) -{ - struct mapped_device *md = q->queuedata; - - return md->saved_make_request_fn(q, bio); /* call __make_request() */ -} - static int dm_request_based(struct mapped_device *md) { return blk_queue_stackable(md->queue); @@ -1437,7 +1427,7 @@ static int dm_request(struct request_queue *q, struct bio *bio) struct mapped_device *md = q->queuedata; if (dm_request_based(md)) - return dm_make_request(q, bio); + return __make_request(q, bio); return _dm_request(q, bio); } @@ -2172,7 +2162,6 @@ static int dm_init_request_based_queue(struct mapped_device *md) return 0; md->queue = q; - md->saved_make_request_fn = md->queue->make_request_fn; dm_init_md_queue(md); blk_queue_softirq_done(md->queue, dm_softirq_done); blk_queue_prep_rq(md->queue, dm_prep_fn); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0e67c45b3bc9..e9c3d9b07630 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -675,6 +675,8 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, struct scsi_ioctl_command __user *); +extern int __make_request(struct request_queue *q, struct bio *bio); + /* * A queue has just exitted congestion. Note this in the global counter of * congested queues, and wake up anyone who was waiting for requests to be From c20e8de27fef9f59869c81c288ad6cf28200e00c Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 12 Sep 2011 12:03:37 +0200 Subject: [PATCH 0348/1596] block: rename __make_request() to blk_queue_bio() Now that it's exported, lets put it in a more sane namespace. Signed-off-by: Jens Axboe --- block/blk-core.c | 6 +++--- drivers/md/dm.c | 2 +- include/linux/blkdev.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 56ef387e7d27..ab673f0b8c30 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -540,7 +540,7 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn, /* * This also sets hw/phys segments, boundary and size */ - blk_queue_make_request(q, __make_request); + blk_queue_make_request(q, blk_queue_bio); q->sg_reserved_size = INT_MAX; @@ -1211,7 +1211,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) blk_rq_bio_prep(req->q, req, bio); } -int __make_request(struct request_queue *q, struct bio *bio) +int blk_queue_bio(struct request_queue *q, struct bio *bio) { const bool sync = !!(bio->bi_rw & REQ_SYNC); struct blk_plug *plug; @@ -1315,7 +1315,7 @@ int __make_request(struct request_queue *q, struct bio *bio) out: return 0; } -EXPORT_SYMBOL_GPL(__make_request); /* for device mapper only */ +EXPORT_SYMBOL_GPL(blk_queue_bio); /* for device mapper only */ /* * If bio->bi_dev is a partition, remap the location diff --git a/drivers/md/dm.c b/drivers/md/dm.c index d8d7b8d9dd28..78b20868bcbc 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1427,7 +1427,7 @@ static int dm_request(struct request_queue *q, struct bio *bio) struct mapped_device *md = q->queuedata; if (dm_request_based(md)) - return __make_request(q, bio); + return blk_queue_bio(q, bio); return _dm_request(q, bio); } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index e9c3d9b07630..085f95414c7f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -675,7 +675,7 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, struct scsi_ioctl_command __user *); -extern int __make_request(struct request_queue *q, struct bio *bio); +extern int blk_queue_bio(struct request_queue *q, struct bio *bio); /* * A queue has just exitted congestion. Note this in the global counter of From 5a7bbad27a410350e64a2d7f5ec18fc73836c14f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 12 Sep 2011 12:12:01 +0200 Subject: [PATCH 0349/1596] block: remove support for bio remapping from ->make_request There is very little benefit in allowing to let a ->make_request instance update the bios device and sector and loop around it in __generic_make_request when we can archive the same through calling generic_make_request from the driver and letting the loop in generic_make_request handle it. Note that various drivers got the return value from ->make_request and returned non-zero values for errors. Signed-off-by: Christoph Hellwig Acked-by: NeilBrown Signed-off-by: Jens Axboe --- arch/m68k/emu/nfblock.c | 3 +- arch/powerpc/sysdev/axonram.c | 8 +- block/blk-core.c | 153 +++++++++++++------------------- drivers/block/aoe/aoeblk.c | 14 ++- drivers/block/brd.c | 4 +- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_req.c | 8 +- drivers/block/loop.c | 5 +- drivers/block/pktcdvd.c | 11 ++- drivers/block/ps3vram.c | 6 +- drivers/block/umem.c | 4 +- drivers/md/dm.c | 14 +-- drivers/md/faulty.c | 14 +-- drivers/md/linear.c | 17 ++-- drivers/md/md.c | 12 +-- drivers/md/md.h | 2 +- drivers/md/multipath.c | 8 +- drivers/md/raid0.c | 22 ++--- drivers/md/raid1.c | 8 +- drivers/md/raid10.c | 19 ++-- drivers/md/raid5.c | 8 +- drivers/s390/block/dcssblk.c | 7 +- drivers/s390/block/xpram.c | 5 +- drivers/staging/zram/zram_drv.c | 8 +- include/linux/blkdev.h | 4 +- 25 files changed, 151 insertions(+), 215 deletions(-) diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c index 48e50f8c1c7e..e3011338ab40 100644 --- a/arch/m68k/emu/nfblock.c +++ b/arch/m68k/emu/nfblock.c @@ -59,7 +59,7 @@ struct nfhd_device { struct gendisk *disk; }; -static int nfhd_make_request(struct request_queue *queue, struct bio *bio) +static void nfhd_make_request(struct request_queue *queue, struct bio *bio) { struct nfhd_device *dev = queue->queuedata; struct bio_vec *bvec; @@ -76,7 +76,6 @@ static int nfhd_make_request(struct request_queue *queue, struct bio *bio) sec += len; } bio_endio(bio, 0); - return 0; } static int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo) diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 265f0f09395a..ba4271919062 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -104,7 +104,7 @@ axon_ram_irq_handler(int irq, void *dev) * axon_ram_make_request - make_request() method for block device * @queue, @bio: see blk_queue_make_request() */ -static int +static void axon_ram_make_request(struct request_queue *queue, struct bio *bio) { struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data; @@ -113,7 +113,6 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) struct bio_vec *vec; unsigned int transfered; unsigned short idx; - int rc = 0; phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT); phys_end = bank->io_addr + bank->size; @@ -121,8 +120,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) bio_for_each_segment(vec, bio, idx) { if (unlikely(phys_mem + vec->bv_len > phys_end)) { bio_io_error(bio); - rc = -ERANGE; - break; + return; } user_mem = page_address(vec->bv_page) + vec->bv_offset; @@ -135,8 +133,6 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) transfered += vec->bv_len; } bio_endio(bio, 0); - - return rc; } /** diff --git a/block/blk-core.c b/block/blk-core.c index ab673f0b8c30..f58e019be67b 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1211,7 +1211,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) blk_rq_bio_prep(req->q, req, bio); } -int blk_queue_bio(struct request_queue *q, struct bio *bio) +void blk_queue_bio(struct request_queue *q, struct bio *bio) { const bool sync = !!(bio->bi_rw & REQ_SYNC); struct blk_plug *plug; @@ -1236,7 +1236,7 @@ int blk_queue_bio(struct request_queue *q, struct bio *bio) * any locks. */ if (attempt_plug_merge(current, q, bio)) - goto out; + return; spin_lock_irq(q->queue_lock); @@ -1312,8 +1312,6 @@ int blk_queue_bio(struct request_queue *q, struct bio *bio) out_unlock: spin_unlock_irq(q->queue_lock); } -out: - return 0; } EXPORT_SYMBOL_GPL(blk_queue_bio); /* for device mapper only */ @@ -1441,112 +1439,85 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors) static inline void __generic_make_request(struct bio *bio) { struct request_queue *q; - sector_t old_sector; - int ret, nr_sectors = bio_sectors(bio); - dev_t old_dev; + int nr_sectors = bio_sectors(bio); int err = -EIO; + char b[BDEVNAME_SIZE]; + struct hd_struct *part; might_sleep(); if (bio_check_eod(bio, nr_sectors)) goto end_io; - /* - * Resolve the mapping until finished. (drivers are - * still free to implement/resolve their own stacking - * by explicitly returning 0) - * - * NOTE: we don't repeat the blk_size check for each new device. - * Stacking drivers are expected to know what they are doing. - */ - old_sector = -1; - old_dev = 0; - do { - char b[BDEVNAME_SIZE]; - struct hd_struct *part; - - q = bdev_get_queue(bio->bi_bdev); - if (unlikely(!q)) { - printk(KERN_ERR - "generic_make_request: Trying to access " - "nonexistent block-device %s (%Lu)\n", - bdevname(bio->bi_bdev, b), - (long long) bio->bi_sector); - goto end_io; - } - - if (unlikely(!(bio->bi_rw & REQ_DISCARD) && - nr_sectors > queue_max_hw_sectors(q))) { - printk(KERN_ERR "bio too big device %s (%u > %u)\n", - bdevname(bio->bi_bdev, b), - bio_sectors(bio), - queue_max_hw_sectors(q)); - goto end_io; - } - - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) - goto end_io; - - part = bio->bi_bdev->bd_part; - if (should_fail_request(part, bio->bi_size) || - should_fail_request(&part_to_disk(part)->part0, - bio->bi_size)) - goto end_io; + q = bdev_get_queue(bio->bi_bdev); + if (unlikely(!q)) { + printk(KERN_ERR + "generic_make_request: Trying to access " + "nonexistent block-device %s (%Lu)\n", + bdevname(bio->bi_bdev, b), + (long long) bio->bi_sector); + goto end_io; + } - /* - * If this device has partitions, remap block n - * of partition p to block n+start(p) of the disk. - */ - blk_partition_remap(bio); + if (unlikely(!(bio->bi_rw & REQ_DISCARD) && + nr_sectors > queue_max_hw_sectors(q))) { + printk(KERN_ERR "bio too big device %s (%u > %u)\n", + bdevname(bio->bi_bdev, b), + bio_sectors(bio), + queue_max_hw_sectors(q)); + goto end_io; + } - if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) - goto end_io; + if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) + goto end_io; - if (old_sector != -1) - trace_block_bio_remap(q, bio, old_dev, old_sector); + part = bio->bi_bdev->bd_part; + if (should_fail_request(part, bio->bi_size) || + should_fail_request(&part_to_disk(part)->part0, + bio->bi_size)) + goto end_io; - old_sector = bio->bi_sector; - old_dev = bio->bi_bdev->bd_dev; + /* + * If this device has partitions, remap block n + * of partition p to block n+start(p) of the disk. + */ + blk_partition_remap(bio); - if (bio_check_eod(bio, nr_sectors)) - goto end_io; + if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) + goto end_io; - /* - * Filter flush bio's early so that make_request based - * drivers without flush support don't have to worry - * about them. - */ - if ((bio->bi_rw & (REQ_FLUSH | REQ_FUA)) && !q->flush_flags) { - bio->bi_rw &= ~(REQ_FLUSH | REQ_FUA); - if (!nr_sectors) { - err = 0; - goto end_io; - } - } + if (bio_check_eod(bio, nr_sectors)) + goto end_io; - if ((bio->bi_rw & REQ_DISCARD) && - (!blk_queue_discard(q) || - ((bio->bi_rw & REQ_SECURE) && - !blk_queue_secdiscard(q)))) { - err = -EOPNOTSUPP; + /* + * Filter flush bio's early so that make_request based + * drivers without flush support don't have to worry + * about them. + */ + if ((bio->bi_rw & (REQ_FLUSH | REQ_FUA)) && !q->flush_flags) { + bio->bi_rw &= ~(REQ_FLUSH | REQ_FUA); + if (!nr_sectors) { + err = 0; goto end_io; } + } - if (blk_throtl_bio(q, &bio)) - goto end_io; - - /* - * If bio = NULL, bio has been throttled and will be submitted - * later. - */ - if (!bio) - break; - - trace_block_bio_queue(q, bio); + if ((bio->bi_rw & REQ_DISCARD) && + (!blk_queue_discard(q) || + ((bio->bi_rw & REQ_SECURE) && + !blk_queue_secdiscard(q)))) { + err = -EOPNOTSUPP; + goto end_io; + } - ret = q->make_request_fn(q, bio); - } while (ret); + if (blk_throtl_bio(q, &bio)) + goto end_io; + /* if bio = NULL, bio has been throttled and will be submitted later. */ + if (!bio) + return; + trace_block_bio_queue(q, bio); + q->make_request_fn(q, bio); return; end_io: diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 528f6318ded1..167ba0af47f5 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -159,7 +159,7 @@ aoeblk_release(struct gendisk *disk, fmode_t mode) return 0; } -static int +static void aoeblk_make_request(struct request_queue *q, struct bio *bio) { struct sk_buff_head queue; @@ -172,25 +172,25 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) if (bio == NULL) { printk(KERN_ERR "aoe: bio is NULL\n"); BUG(); - return 0; + return; } d = bio->bi_bdev->bd_disk->private_data; if (d == NULL) { printk(KERN_ERR "aoe: bd_disk->private_data is NULL\n"); BUG(); bio_endio(bio, -ENXIO); - return 0; + return; } else if (bio->bi_io_vec == NULL) { printk(KERN_ERR "aoe: bi_io_vec is NULL\n"); BUG(); bio_endio(bio, -ENXIO); - return 0; + return; } buf = mempool_alloc(d->bufpool, GFP_NOIO); if (buf == NULL) { printk(KERN_INFO "aoe: buf allocation failure\n"); bio_endio(bio, -ENOMEM); - return 0; + return; } memset(buf, 0, sizeof(*buf)); INIT_LIST_HEAD(&buf->bufs); @@ -211,7 +211,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); bio_endio(bio, -ENXIO); - return 0; + return; } list_add_tail(&buf->bufs, &d->bufq); @@ -222,8 +222,6 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) spin_unlock_irqrestore(&d->lock, flags); aoenet_xmit(&queue); - - return 0; } static int diff --git a/drivers/block/brd.c b/drivers/block/brd.c index dba1c32e1ddf..d22119d49e53 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -323,7 +323,7 @@ static int brd_do_bvec(struct brd_device *brd, struct page *page, return err; } -static int brd_make_request(struct request_queue *q, struct bio *bio) +static void brd_make_request(struct request_queue *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct brd_device *brd = bdev->bd_disk->private_data; @@ -359,8 +359,6 @@ static int brd_make_request(struct request_queue *q, struct bio *bio) out: bio_endio(bio, err); - - return 0; } #ifdef CONFIG_BLK_DEV_XIP diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index ef2ceed3be4b..36eee3969a98 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1507,7 +1507,7 @@ extern void drbd_free_mdev(struct drbd_conf *mdev); extern int proc_details; /* drbd_req */ -extern int drbd_make_request(struct request_queue *q, struct bio *bio); +extern void drbd_make_request(struct request_queue *q, struct bio *bio); extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec); extern int is_valid_ar_handle(struct drbd_request *, sector_t); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3424d675b769..4a0f314086e5 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1073,7 +1073,7 @@ static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write) return 0; } -int drbd_make_request(struct request_queue *q, struct bio *bio) +void drbd_make_request(struct request_queue *q, struct bio *bio) { unsigned int s_enr, e_enr; struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; @@ -1081,7 +1081,7 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) { bio_endio(bio, -EPERM); - return 0; + return; } start_time = jiffies; @@ -1100,7 +1100,8 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) if (likely(s_enr == e_enr)) { inc_ap_bio(mdev, 1); - return drbd_make_request_common(mdev, bio, start_time); + drbd_make_request_common(mdev, bio, start_time); + return; } /* can this bio be split generically? @@ -1148,7 +1149,6 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) bio_pair_release(bp); } - return 0; } /* This is called by bio_add_page(). With this function we reduce diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 76c8da78212b..8360239d553c 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -514,7 +514,7 @@ static struct bio *loop_get_bio(struct loop_device *lo) return bio_list_pop(&lo->lo_bio_list); } -static int loop_make_request(struct request_queue *q, struct bio *old_bio) +static void loop_make_request(struct request_queue *q, struct bio *old_bio) { struct loop_device *lo = q->queuedata; int rw = bio_rw(old_bio); @@ -532,12 +532,11 @@ static int loop_make_request(struct request_queue *q, struct bio *old_bio) loop_add_bio(lo, old_bio); wake_up(&lo->lo_event); spin_unlock_irq(&lo->lo_lock); - return 0; + return; out: spin_unlock_irq(&lo->lo_lock); bio_io_error(old_bio); - return 0; } struct switch_request { diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index e133f094ab08..a63b0a2b7805 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2444,7 +2444,7 @@ static void pkt_end_io_read_cloned(struct bio *bio, int err) pkt_bio_finished(pd); } -static int pkt_make_request(struct request_queue *q, struct bio *bio) +static void pkt_make_request(struct request_queue *q, struct bio *bio) { struct pktcdvd_device *pd; char b[BDEVNAME_SIZE]; @@ -2473,7 +2473,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) cloned_bio->bi_end_io = pkt_end_io_read_cloned; pd->stats.secs_r += bio->bi_size >> 9; pkt_queue_bio(pd, cloned_bio); - return 0; + return; } if (!test_bit(PACKET_WRITABLE, &pd->flags)) { @@ -2509,7 +2509,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) pkt_make_request(q, &bp->bio1); pkt_make_request(q, &bp->bio2); bio_pair_release(bp); - return 0; + return; } } @@ -2533,7 +2533,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) } spin_unlock(&pkt->lock); spin_unlock(&pd->cdrw.active_list_lock); - return 0; + return; } else { blocked_bio = 1; } @@ -2584,10 +2584,9 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) */ wake_up(&pd->wqueue); } - return 0; + return; end_io: bio_io_error(bio); - return 0; } diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index b3bdb8af89cf..7fad7af87eb2 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -596,7 +596,7 @@ static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, return next; } -static int ps3vram_make_request(struct request_queue *q, struct bio *bio) +static void ps3vram_make_request(struct request_queue *q, struct bio *bio) { struct ps3_system_bus_device *dev = q->queuedata; struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); @@ -610,13 +610,11 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) spin_unlock_irq(&priv->lock); if (busy) - return 0; + return; do { bio = ps3vram_do_bio(dev, bio); } while (bio); - - return 0; } static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 031ca720d926..aa2712060bfb 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -513,7 +513,7 @@ static void process_page(unsigned long data) } } -static int mm_make_request(struct request_queue *q, struct bio *bio) +static void mm_make_request(struct request_queue *q, struct bio *bio) { struct cardinfo *card = q->queuedata; pr_debug("mm_make_request %llu %u\n", @@ -525,7 +525,7 @@ static int mm_make_request(struct request_queue *q, struct bio *bio) card->biotail = &bio->bi_next; spin_unlock_irq(&card->lock); - return 0; + return; } static irqreturn_t mm_interrupt(int irq, void *__card) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 78b20868bcbc..7b986e77b75e 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1388,7 +1388,7 @@ static int dm_merge_bvec(struct request_queue *q, * The request function that just remaps the bio built up by * dm_merge_bvec. */ -static int _dm_request(struct request_queue *q, struct bio *bio) +static void _dm_request(struct request_queue *q, struct bio *bio) { int rw = bio_data_dir(bio); struct mapped_device *md = q->queuedata; @@ -1409,12 +1409,12 @@ static int _dm_request(struct request_queue *q, struct bio *bio) queue_io(md, bio); else bio_io_error(bio); - return 0; + return; } __split_and_process_bio(md, bio); up_read(&md->io_lock); - return 0; + return; } static int dm_request_based(struct mapped_device *md) @@ -1422,14 +1422,14 @@ static int dm_request_based(struct mapped_device *md) return blk_queue_stackable(md->queue); } -static int dm_request(struct request_queue *q, struct bio *bio) +static void dm_request(struct request_queue *q, struct bio *bio) { struct mapped_device *md = q->queuedata; if (dm_request_based(md)) - return blk_queue_bio(q, bio); - - return _dm_request(q, bio); + blk_queue_bio(q, bio); + else + _dm_request(q, bio); } void dm_dispatch_request(struct request *rq) diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 23078dabb6df..5ef304d4341c 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -169,7 +169,7 @@ static void add_sector(conf_t *conf, sector_t start, int mode) conf->nfaults = n+1; } -static int make_request(mddev_t *mddev, struct bio *bio) +static void make_request(mddev_t *mddev, struct bio *bio) { conf_t *conf = mddev->private; int failit = 0; @@ -181,7 +181,7 @@ static int make_request(mddev_t *mddev, struct bio *bio) * just fail immediately */ bio_endio(bio, -EIO); - return 0; + return; } if (check_sector(conf, bio->bi_sector, bio->bi_sector+(bio->bi_size>>9), @@ -211,15 +211,15 @@ static int make_request(mddev_t *mddev, struct bio *bio) } if (failit) { struct bio *b = bio_clone_mddev(bio, GFP_NOIO, mddev); + b->bi_bdev = conf->rdev->bdev; b->bi_private = bio; b->bi_end_io = faulty_fail; - generic_make_request(b); - return 0; - } else { + bio = b; + } else bio->bi_bdev = conf->rdev->bdev; - return 1; - } + + generic_make_request(bio); } static void status(struct seq_file *seq, mddev_t *mddev) diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 6cd2c313e800..c6ee491d98e7 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -264,14 +264,14 @@ static int linear_stop (mddev_t *mddev) return 0; } -static int linear_make_request (mddev_t *mddev, struct bio *bio) +static void linear_make_request (mddev_t *mddev, struct bio *bio) { dev_info_t *tmp_dev; sector_t start_sector; if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } rcu_read_lock(); @@ -293,7 +293,7 @@ static int linear_make_request (mddev_t *mddev, struct bio *bio) (unsigned long long)start_sector); rcu_read_unlock(); bio_io_error(bio); - return 0; + return; } if (unlikely(bio->bi_sector + (bio->bi_size >> 9) > tmp_dev->end_sector)) { @@ -307,20 +307,17 @@ static int linear_make_request (mddev_t *mddev, struct bio *bio) bp = bio_split(bio, end_sector - bio->bi_sector); - if (linear_make_request(mddev, &bp->bio1)) - generic_make_request(&bp->bio1); - if (linear_make_request(mddev, &bp->bio2)) - generic_make_request(&bp->bio2); + linear_make_request(mddev, &bp->bio1); + linear_make_request(mddev, &bp->bio2); bio_pair_release(bp); - return 0; + return; } bio->bi_bdev = tmp_dev->rdev->bdev; bio->bi_sector = bio->bi_sector - start_sector + tmp_dev->rdev->data_offset; rcu_read_unlock(); - - return 1; + generic_make_request(bio); } static void linear_status (struct seq_file *seq, mddev_t *mddev) diff --git a/drivers/md/md.c b/drivers/md/md.c index 8e221a20f5d9..5c2178562c96 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -330,18 +330,17 @@ static DEFINE_SPINLOCK(all_mddevs_lock); * call has finished, the bio has been linked into some internal structure * and so is visible to ->quiesce(), so we don't need the refcount any more. */ -static int md_make_request(struct request_queue *q, struct bio *bio) +static void md_make_request(struct request_queue *q, struct bio *bio) { const int rw = bio_data_dir(bio); mddev_t *mddev = q->queuedata; - int rv; int cpu; unsigned int sectors; if (mddev == NULL || mddev->pers == NULL || !mddev->ready) { bio_io_error(bio); - return 0; + return; } smp_rmb(); /* Ensure implications of 'active' are visible */ rcu_read_lock(); @@ -366,7 +365,7 @@ static int md_make_request(struct request_queue *q, struct bio *bio) * go away inside make_request */ sectors = bio_sectors(bio); - rv = mddev->pers->make_request(mddev, bio); + mddev->pers->make_request(mddev, bio); cpu = part_stat_lock(); part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]); @@ -375,8 +374,6 @@ static int md_make_request(struct request_queue *q, struct bio *bio) if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended) wake_up(&mddev->sb_wait); - - return rv; } /* mddev_suspend makes sure no new requests are submitted @@ -475,8 +472,7 @@ static void md_submit_flush_data(struct work_struct *ws) bio_endio(bio, 0); else { bio->bi_rw &= ~REQ_FLUSH; - if (mddev->pers->make_request(mddev, bio)) - generic_make_request(bio); + mddev->pers->make_request(mddev, bio); } mddev->flush_bio = NULL; diff --git a/drivers/md/md.h b/drivers/md/md.h index 1e586bb4452e..bd47847cf7ca 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -424,7 +424,7 @@ struct mdk_personality int level; struct list_head list; struct module *owner; - int (*make_request)(mddev_t *mddev, struct bio *bio); + void (*make_request)(mddev_t *mddev, struct bio *bio); int (*run)(mddev_t *mddev); int (*stop)(mddev_t *mddev); void (*status)(struct seq_file *seq, mddev_t *mddev); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 3535c23af288..407cb5691425 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -106,7 +106,7 @@ static void multipath_end_request(struct bio *bio, int error) rdev_dec_pending(rdev, conf->mddev); } -static int multipath_make_request(mddev_t *mddev, struct bio * bio) +static void multipath_make_request(mddev_t *mddev, struct bio * bio) { multipath_conf_t *conf = mddev->private; struct multipath_bh * mp_bh; @@ -114,7 +114,7 @@ static int multipath_make_request(mddev_t *mddev, struct bio * bio) if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } mp_bh = mempool_alloc(conf->pool, GFP_NOIO); @@ -126,7 +126,7 @@ static int multipath_make_request(mddev_t *mddev, struct bio * bio) if (mp_bh->path < 0) { bio_endio(bio, -EIO); mempool_free(mp_bh, conf->pool); - return 0; + return; } multipath = conf->multipaths + mp_bh->path; @@ -137,7 +137,7 @@ static int multipath_make_request(mddev_t *mddev, struct bio * bio) mp_bh->bio.bi_end_io = multipath_end_request; mp_bh->bio.bi_private = mp_bh; generic_make_request(&mp_bh->bio); - return 0; + return; } static void multipath_status (struct seq_file *seq, mddev_t *mddev) diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index e86bf3682e1e..4066615d61af 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -466,7 +466,7 @@ static inline int is_io_in_chunk_boundary(mddev_t *mddev, } } -static int raid0_make_request(mddev_t *mddev, struct bio *bio) +static void raid0_make_request(mddev_t *mddev, struct bio *bio) { unsigned int chunk_sects; sector_t sector_offset; @@ -475,7 +475,7 @@ static int raid0_make_request(mddev_t *mddev, struct bio *bio) if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } chunk_sects = mddev->chunk_sectors; @@ -495,13 +495,10 @@ static int raid0_make_request(mddev_t *mddev, struct bio *bio) else bp = bio_split(bio, chunk_sects - sector_div(sector, chunk_sects)); - if (raid0_make_request(mddev, &bp->bio1)) - generic_make_request(&bp->bio1); - if (raid0_make_request(mddev, &bp->bio2)) - generic_make_request(&bp->bio2); - + raid0_make_request(mddev, &bp->bio1); + raid0_make_request(mddev, &bp->bio2); bio_pair_release(bp); - return 0; + return; } sector_offset = bio->bi_sector; @@ -511,10 +508,9 @@ static int raid0_make_request(mddev_t *mddev, struct bio *bio) bio->bi_bdev = tmp_dev->bdev; bio->bi_sector = sector_offset + zone->dev_start + tmp_dev->data_offset; - /* - * Let the main block layer submit the IO and resolve recursion: - */ - return 1; + + generic_make_request(bio); + return; bad_map: printk("md/raid0:%s: make_request bug: can't convert block across chunks" @@ -523,7 +519,7 @@ static int raid0_make_request(mddev_t *mddev, struct bio *bio) (unsigned long long)bio->bi_sector, bio->bi_size >> 10); bio_io_error(bio); - return 0; + return; } static void raid0_status(struct seq_file *seq, mddev_t *mddev) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 32323f0afd89..97f2a5f977b1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -785,7 +785,7 @@ static void alloc_behind_pages(struct bio *bio, r1bio_t *r1_bio) PRINTK("%dB behind alloc failed, doing sync I/O\n", bio->bi_size); } -static int make_request(mddev_t *mddev, struct bio * bio) +static void make_request(mddev_t *mddev, struct bio * bio) { conf_t *conf = mddev->private; mirror_info_t *mirror; @@ -870,7 +870,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) if (rdisk < 0) { /* couldn't find anywhere to read from */ raid_end_bio_io(r1_bio); - return 0; + return; } mirror = conf->mirrors + rdisk; @@ -928,7 +928,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) goto read_again; } else generic_make_request(read_bio); - return 0; + return; } /* @@ -1119,8 +1119,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) if (do_sync || !bitmap || !plugged) md_wakeup_thread(mddev->thread); - - return 0; } static void status(struct seq_file *seq, mddev_t *mddev) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 8b29cd4f01c8..04b625e1cb60 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -825,7 +825,7 @@ static void unfreeze_array(conf_t *conf) spin_unlock_irq(&conf->resync_lock); } -static int make_request(mddev_t *mddev, struct bio * bio) +static void make_request(mddev_t *mddev, struct bio * bio) { conf_t *conf = mddev->private; mirror_info_t *mirror; @@ -844,7 +844,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } /* If this request crosses a chunk boundary, we need to @@ -876,10 +876,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) conf->nr_waiting++; spin_unlock_irq(&conf->resync_lock); - if (make_request(mddev, &bp->bio1)) - generic_make_request(&bp->bio1); - if (make_request(mddev, &bp->bio2)) - generic_make_request(&bp->bio2); + make_request(mddev, &bp->bio1); + make_request(mddev, &bp->bio2); spin_lock_irq(&conf->resync_lock); conf->nr_waiting--; @@ -887,14 +885,14 @@ static int make_request(mddev_t *mddev, struct bio * bio) spin_unlock_irq(&conf->resync_lock); bio_pair_release(bp); - return 0; + return; bad_map: printk("md/raid10:%s: make_request bug: can't convert block across chunks" " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects/2, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); bio_io_error(bio); - return 0; + return; } md_write_start(mddev, bio); @@ -937,7 +935,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) slot = r10_bio->read_slot; if (disk < 0) { raid_end_bio_io(r10_bio); - return 0; + return; } mirror = conf->mirrors + disk; @@ -985,7 +983,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) goto read_again; } else generic_make_request(read_bio); - return 0; + return; } /* @@ -1157,7 +1155,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) if (do_sync || !mddev->bitmap || !plugged) md_wakeup_thread(mddev->thread); - return 0; } static void status(struct seq_file *seq, mddev_t *mddev) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index dbae459fb02d..96b7f6a1b6f2 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3695,7 +3695,7 @@ static struct stripe_head *__get_priority_stripe(raid5_conf_t *conf) return sh; } -static int make_request(mddev_t *mddev, struct bio * bi) +static void make_request(mddev_t *mddev, struct bio * bi) { raid5_conf_t *conf = mddev->private; int dd_idx; @@ -3708,7 +3708,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) if (unlikely(bi->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bi); - return 0; + return; } md_write_start(mddev, bi); @@ -3716,7 +3716,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) if (rw == READ && mddev->reshape_position == MaxSector && chunk_aligned_read(mddev,bi)) - return 0; + return; logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); last_sector = bi->bi_sector + (bi->bi_size>>9); @@ -3851,8 +3851,6 @@ static int make_request(mddev_t *mddev, struct bio * bi) bio_endio(bi, 0); } - - return 0; } static sector_t raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 9b43ae94beba..a5a55da2a1ac 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -27,7 +27,7 @@ static int dcssblk_open(struct block_device *bdev, fmode_t mode); static int dcssblk_release(struct gendisk *disk, fmode_t mode); -static int dcssblk_make_request(struct request_queue *q, struct bio *bio); +static void dcssblk_make_request(struct request_queue *q, struct bio *bio); static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, void **kaddr, unsigned long *pfn); @@ -814,7 +814,7 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) return rc; } -static int +static void dcssblk_make_request(struct request_queue *q, struct bio *bio) { struct dcssblk_dev_info *dev_info; @@ -871,10 +871,9 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) bytes_done += bvec->bv_len; } bio_endio(bio, 0); - return 0; + return; fail: bio_io_error(bio); - return 0; } static int diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 1f6a4d894e73..98f3e4ade924 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -181,7 +181,7 @@ static unsigned long xpram_highest_page_index(void) /* * Block device make request function. */ -static int xpram_make_request(struct request_queue *q, struct bio *bio) +static void xpram_make_request(struct request_queue *q, struct bio *bio) { xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data; struct bio_vec *bvec; @@ -221,10 +221,9 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } set_bit(BIO_UPTODATE, &bio->bi_flags); bio_endio(bio, 0); - return 0; + return; fail: bio_io_error(bio); - return 0; } static int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo) diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index d70ec1ad10de..02589cab6710 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -556,24 +556,22 @@ static inline int valid_io_request(struct zram *zram, struct bio *bio) /* * Handler function for all zram I/O requests. */ -static int zram_make_request(struct request_queue *queue, struct bio *bio) +static void zram_make_request(struct request_queue *queue, struct bio *bio) { struct zram *zram = queue->queuedata; if (!valid_io_request(zram, bio)) { zram_stat64_inc(zram, &zram->stats.invalid_io); bio_io_error(bio); - return 0; + return; } if (unlikely(!zram->init_done) && zram_init_device(zram)) { bio_io_error(bio); - return 0; + return; } __zram_make_request(zram, bio, bio_data_dir(bio)); - - return 0; } void zram_reset_device(struct zram *zram) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 085f95414c7f..c712efdafc3f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -193,7 +193,7 @@ struct request_pm_state #include typedef void (request_fn_proc) (struct request_queue *q); -typedef int (make_request_fn) (struct request_queue *q, struct bio *bio); +typedef void (make_request_fn) (struct request_queue *q, struct bio *bio); typedef int (prep_rq_fn) (struct request_queue *, struct request *); typedef void (unprep_rq_fn) (struct request_queue *, struct request *); @@ -675,7 +675,7 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, struct scsi_ioctl_command __user *); -extern int blk_queue_bio(struct request_queue *q, struct bio *bio); +extern void blk_queue_bio(struct request_queue *q, struct bio *bio); /* * A queue has just exitted congestion. Note this in the global counter of From a2f5203fec3c06d68a6bb45ad41f2adebf9ac5e0 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:29 +0900 Subject: [PATCH 0350/1596] DMA: PL330: Add support runtime PM for PL330 DMAC Signed-off-by: Boojin Kim Acked-by: Jassi Brar Acked-by: Linus Walleij Acked-by: Vinod Koul Cc: Dan Williams Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 75 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 00eee59e8b33..0b99af18f9a1 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -17,6 +17,7 @@ #include #include #include +#include #define NR_DEFAULT_DESC 16 @@ -83,6 +84,8 @@ struct dma_pl330_dmac { /* Peripheral channels connected to this DMAC */ struct dma_pl330_chan *peripherals; /* keep at end */ + + struct clk *clk; }; struct dma_pl330_desc { @@ -696,6 +699,30 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) goto probe_err1; } + pdmac->clk = clk_get(&adev->dev, "dma"); + if (IS_ERR(pdmac->clk)) { + dev_err(&adev->dev, "Cannot get operation clock.\n"); + ret = -EINVAL; + goto probe_err1; + } + + amba_set_drvdata(adev, pdmac); + +#ifdef CONFIG_PM_RUNTIME + /* to use the runtime PM helper functions */ + pm_runtime_enable(&adev->dev); + + /* enable the power domain */ + if (pm_runtime_get_sync(&adev->dev)) { + dev_err(&adev->dev, "failed to get runtime pm\n"); + ret = -ENODEV; + goto probe_err1; + } +#else + /* enable dma clk */ + clk_enable(pdmac->clk); +#endif + irq = adev->irq[0]; ret = request_irq(irq, pl330_irq_handler, 0, dev_name(&adev->dev), pi); @@ -771,8 +798,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) goto probe_err4; } - amba_set_drvdata(adev, pdmac); - dev_info(&adev->dev, "Loaded driver for PL330 DMAC-%d\n", adev->periphid); dev_info(&adev->dev, @@ -833,6 +858,13 @@ static int __devexit pl330_remove(struct amba_device *adev) res = &adev->res; release_mem_region(res->start, resource_size(res)); +#ifdef CONFIG_PM_RUNTIME + pm_runtime_put(&adev->dev); + pm_runtime_disable(&adev->dev); +#else + clk_disable(pdmac->clk); +#endif + kfree(pdmac); return 0; @@ -846,10 +878,49 @@ static struct amba_id pl330_ids[] = { { 0, 0 }, }; +#ifdef CONFIG_PM_RUNTIME +static int pl330_runtime_suspend(struct device *dev) +{ + struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev); + + if (!pdmac) { + dev_err(dev, "failed to get dmac\n"); + return -ENODEV; + } + + clk_disable(pdmac->clk); + + return 0; +} + +static int pl330_runtime_resume(struct device *dev) +{ + struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev); + + if (!pdmac) { + dev_err(dev, "failed to get dmac\n"); + return -ENODEV; + } + + clk_enable(pdmac->clk); + + return 0; +} +#else +#define pl330_runtime_suspend NULL +#define pl330_runtime_resume NULL +#endif /* CONFIG_PM_RUNTIME */ + +static const struct dev_pm_ops pl330_pm_ops = { + .runtime_suspend = pl330_runtime_suspend, + .runtime_resume = pl330_runtime_resume, +}; + static struct amba_driver pl330_driver = { .drv = { .owner = THIS_MODULE, .name = "dma-pl330", + .pm = &pl330_pm_ops, }, .id_table = pl330_ids, .probe = pl330_probe, From 1b9bb715e7c4c189c4215a11a09e2ccb16598d86 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:30 +0900 Subject: [PATCH 0351/1596] DMA: PL330: Update PL330 DMA API driver This patch updates following 3 items. 1. Removes unneccessary code. 2. Add AMBA, PL330 configuration 3. Change the meaning of 'peri_id' variable from PL330 event number to specific dma id by user. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Cc: Dan Williams Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 3 ++- drivers/dma/pl330.c | 14 +++++++++----- include/linux/amba/pl330.h | 6 +----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 2e3b3d38c465..ab8f469f5cf8 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -193,7 +193,8 @@ config ARCH_HAS_ASYNC_TX_FIND_CHANNEL config PL330_DMA tristate "DMA API Driver for PL330" select DMA_ENGINE - depends on PL330 + depends on ARM_AMBA + select PL330 help Select if your platform has one or more PL330 DMACs. You need to provide platform specific settings via diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 0b99af18f9a1..d5829c734fad 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -18,6 +18,7 @@ #include #include #include +#include #define NR_DEFAULT_DESC 16 @@ -69,6 +70,10 @@ struct dma_pl330_chan { * NULL if the channel is available to be acquired. */ void *pl330_chid; + + /* For D-to-M and M-to-D channels */ + int burst_sz; /* the peripheral fifo width */ + dma_addr_t fifo_addr; }; struct dma_pl330_dmac { @@ -456,7 +461,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) if (peri) { desc->req.rqtype = peri->rqtype; - desc->req.peri = peri->peri_id; + desc->req.peri = pch->chan.chan_id; } else { desc->req.rqtype = MEMTOMEM; desc->req.peri = 0; @@ -582,7 +587,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct dma_pl330_peri *peri = chan->private; struct scatterlist *sg; unsigned long flags; - int i, burst_size; + int i; dma_addr_t addr; if (unlikely(!pch || !sgl || !sg_len || !peri)) @@ -598,8 +603,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, return NULL; } - addr = peri->fifo_addr; - burst_size = peri->burst_sz; + addr = pch->fifo_addr; first = NULL; @@ -647,7 +651,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, sg_dma_address(sg), addr, sg_dma_len(sg)); } - desc->rqcfg.brst_size = burst_size; + desc->rqcfg.brst_size = pch->burst_sz; desc->rqcfg.brst_len = 1; } diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h index cbee7de7dd36..d12f077a6daf 100644 --- a/include/linux/amba/pl330.h +++ b/include/linux/amba/pl330.h @@ -19,12 +19,8 @@ struct dma_pl330_peri { * Peri_Req i/f of the DMAC that is * peripheral could be reached from. */ - u8 peri_id; /* {0, 31} */ + u8 peri_id; /* specific dma id */ enum pl330_reqtype rqtype; - - /* For M->D and D->M Channels */ - int burst_sz; /* in power of 2 */ - dma_addr_t fifo_addr; }; struct dma_pl330_platdata { From 1d0c1d606d787e833ee3bd9e1cda640e75c4681a Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:31 +0900 Subject: [PATCH 0352/1596] DMA: PL330: Support DMA_SLAVE_CONFIG command Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Cc: Dan Williams Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 49 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index d5829c734fad..e7f9d1d3d81a 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -73,6 +73,7 @@ struct dma_pl330_chan { /* For D-to-M and M-to-D channels */ int burst_sz; /* the peripheral fifo width */ + int burst_len; /* the number of burst */ dma_addr_t fifo_addr; }; @@ -263,23 +264,47 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned struct dma_pl330_chan *pch = to_pchan(chan); struct dma_pl330_desc *desc; unsigned long flags; + struct dma_pl330_dmac *pdmac = pch->dmac; + struct dma_slave_config *slave_config; - /* Only supports DMA_TERMINATE_ALL */ - if (cmd != DMA_TERMINATE_ALL) - return -ENXIO; + switch (cmd) { + case DMA_TERMINATE_ALL: + spin_lock_irqsave(&pch->lock, flags); - spin_lock_irqsave(&pch->lock, flags); + /* FLUSH the PL330 Channel thread */ + pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH); - /* FLUSH the PL330 Channel thread */ - pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH); - - /* Mark all desc done */ - list_for_each_entry(desc, &pch->work_list, node) - desc->status = DONE; + /* Mark all desc done */ + list_for_each_entry(desc, &pch->work_list, node) + desc->status = DONE; - spin_unlock_irqrestore(&pch->lock, flags); + spin_unlock_irqrestore(&pch->lock, flags); - pl330_tasklet((unsigned long) pch); + pl330_tasklet((unsigned long) pch); + break; + case DMA_SLAVE_CONFIG: + slave_config = (struct dma_slave_config *)arg; + + if (slave_config->direction == DMA_TO_DEVICE) { + if (slave_config->dst_addr) + pch->fifo_addr = slave_config->dst_addr; + if (slave_config->dst_addr_width) + pch->burst_sz = __ffs(slave_config->dst_addr_width); + if (slave_config->dst_maxburst) + pch->burst_len = slave_config->dst_maxburst; + } else if (slave_config->direction == DMA_FROM_DEVICE) { + if (slave_config->src_addr) + pch->fifo_addr = slave_config->src_addr; + if (slave_config->src_addr_width) + pch->burst_sz = __ffs(slave_config->src_addr_width); + if (slave_config->src_maxburst) + pch->burst_len = slave_config->src_maxburst; + } + break; + default: + dev_err(pch->dmac->pif.dev, "Not supported command.\n"); + return -ENXIO; + } return 0; } From ae43b886f174297366d4e09a008ad8e6592d95df Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:32 +0900 Subject: [PATCH 0353/1596] DMA: PL330: Remove the start operation for handling DMA_TERMINATE_ALL command Original code carries out the start operation after flush operation. But start operation is not required for DMA_TERMINATE_ALL command. So, this patch removes the unnecessary start operation and only carries out the flush operation for handling DMA_TERMINATE_ALL command. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Cc: Dan Williams Signed-off-by: Kukjin Kim [Fixed typos in changelog] Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index e7f9d1d3d81a..59943ec1e74a 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -262,10 +262,11 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { struct dma_pl330_chan *pch = to_pchan(chan); - struct dma_pl330_desc *desc; + struct dma_pl330_desc *desc, *_dt; unsigned long flags; struct dma_pl330_dmac *pdmac = pch->dmac; struct dma_slave_config *slave_config; + LIST_HEAD(list); switch (cmd) { case DMA_TERMINATE_ALL: @@ -275,12 +276,14 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH); /* Mark all desc done */ - list_for_each_entry(desc, &pch->work_list, node) + list_for_each_entry_safe(desc, _dt, &pch->work_list , node) { desc->status = DONE; + pch->completed = desc->txd.cookie; + list_move_tail(&desc->node, &list); + } + list_splice_tail_init(&list, &pdmac->desc_pool); spin_unlock_irqrestore(&pch->lock, flags); - - pl330_tasklet((unsigned long) pch); break; case DMA_SLAVE_CONFIG: slave_config = (struct dma_slave_config *)arg; From 42bc9cf45939c26a5c5eb946d4fd35f1a7b0f9f8 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:33 +0900 Subject: [PATCH 0354/1596] DMA: PL330: Add DMA_CYCLIC capability This patch adds DMA_CYCLIC capability that is used for audio driver. DMA driver activated with it reuses the dma requests that were submitted through tx_submit(). Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Cc: Dan Williams Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 84 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 59943ec1e74a..621134fdba4c 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -75,6 +75,9 @@ struct dma_pl330_chan { int burst_sz; /* the peripheral fifo width */ int burst_len; /* the number of burst */ dma_addr_t fifo_addr; + + /* for cyclic capability */ + bool cyclic; }; struct dma_pl330_dmac { @@ -161,6 +164,31 @@ static inline void free_desc_list(struct list_head *list) spin_unlock_irqrestore(&pdmac->pool_lock, flags); } +static inline void handle_cyclic_desc_list(struct list_head *list) +{ + struct dma_pl330_desc *desc; + struct dma_pl330_chan *pch; + unsigned long flags; + + if (list_empty(list)) + return; + + list_for_each_entry(desc, list, node) { + dma_async_tx_callback callback; + + /* Change status to reload it */ + desc->status = PREP; + pch = desc->pchan; + callback = desc->txd.callback; + if (callback) + callback(desc->txd.callback_param); + } + + spin_lock_irqsave(&pch->lock, flags); + list_splice_tail_init(list, &pch->work_list); + spin_unlock_irqrestore(&pch->lock, flags); +} + static inline void fill_queue(struct dma_pl330_chan *pch) { struct dma_pl330_desc *desc; @@ -214,7 +242,10 @@ static void pl330_tasklet(unsigned long data) spin_unlock_irqrestore(&pch->lock, flags); - free_desc_list(&list); + if (pch->cyclic) + handle_cyclic_desc_list(&list); + else + free_desc_list(&list); } static void dma_pl330_rqcb(void *token, enum pl330_op_err err) @@ -245,6 +276,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) spin_lock_irqsave(&pch->lock, flags); pch->completed = chan->cookie = 1; + pch->cyclic = false; pch->pl330_chid = pl330_request_channel(&pdmac->pif); if (!pch->pl330_chid) { @@ -324,6 +356,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan) pl330_release_channel(pch->pl330_chid); pch->pl330_chid = NULL; + if (pch->cyclic) + list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); + spin_unlock_irqrestore(&pch->lock, flags); } @@ -560,6 +595,51 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) return burst_len; } +static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t dma_addr, size_t len, + size_t period_len, enum dma_data_direction direction) +{ + struct dma_pl330_desc *desc; + struct dma_pl330_chan *pch = to_pchan(chan); + dma_addr_t dst; + dma_addr_t src; + + desc = pl330_get_desc(pch); + if (!desc) { + dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n", + __func__, __LINE__); + return NULL; + } + + switch (direction) { + case DMA_TO_DEVICE: + desc->rqcfg.src_inc = 1; + desc->rqcfg.dst_inc = 0; + src = dma_addr; + dst = pch->fifo_addr; + break; + case DMA_FROM_DEVICE: + desc->rqcfg.src_inc = 0; + desc->rqcfg.dst_inc = 1; + src = pch->fifo_addr; + dst = dma_addr; + break; + default: + dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n", + __func__, __LINE__); + return NULL; + } + + desc->rqcfg.brst_size = pch->burst_sz; + desc->rqcfg.brst_len = 1; + + pch->cyclic = true; + + fill_px(&desc->px, dst, src, period_len); + + return &desc->txd; +} + static struct dma_async_tx_descriptor * pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) @@ -791,6 +871,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) case MEMTODEV: case DEVTOMEM: dma_cap_set(DMA_SLAVE, pd->cap_mask); + dma_cap_set(DMA_CYCLIC, pd->cap_mask); break; default: dev_err(&adev->dev, "DEVTODEV Not Supported\n"); @@ -819,6 +900,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pd->device_alloc_chan_resources = pl330_alloc_chan_resources; pd->device_free_chan_resources = pl330_free_chan_resources; pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy; + pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic; pd->device_tx_status = pl330_tx_status; pd->device_prep_slave_sg = pl330_prep_slave_sg; pd->device_control = pl330_control; From aa0de00e4b9b3adba5db5ef5ee01e61b1b2e4329 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:34 +0900 Subject: [PATCH 0355/1596] ARM: SAMSUNG: Update to use PL330-DMA driver This patch adds to support PL330-DMA driver on DMADEVICE for S5P SoCs. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/mach-exynos4/include/mach/dma.h | 4 ++-- arch/arm/mach-s5p64x0/include/mach/dma.h | 2 +- arch/arm/mach-s5pc100/include/mach/dma.h | 2 +- arch/arm/mach-s5pv210/include/mach/dma.h | 2 +- arch/arm/plat-samsung/Kconfig | 9 +++++++++ .../include/plat/{s3c-dma-pl330.h => dma-pl330.h} | 8 ++++---- arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h | 2 +- 7 files changed, 19 insertions(+), 10 deletions(-) rename arch/arm/plat-samsung/include/plat/{s3c-dma-pl330.h => dma-pl330.h} (93%) diff --git a/arch/arm/mach-exynos4/include/mach/dma.h b/arch/arm/mach-exynos4/include/mach/dma.h index 81209eb1409b..201842a3769e 100644 --- a/arch/arm/mach-exynos4/include/mach/dma.h +++ b/arch/arm/mach-exynos4/include/mach/dma.h @@ -20,7 +20,7 @@ #ifndef __MACH_DMA_H #define __MACH_DMA_H -/* This platform uses the common S3C DMA API driver for PL330 */ -#include +/* This platform uses the common DMA API driver for PL330 */ +#include #endif /* __MACH_DMA_H */ diff --git a/arch/arm/mach-s5p64x0/include/mach/dma.h b/arch/arm/mach-s5p64x0/include/mach/dma.h index 81209eb1409b..1beae2cca6a3 100644 --- a/arch/arm/mach-s5p64x0/include/mach/dma.h +++ b/arch/arm/mach-s5p64x0/include/mach/dma.h @@ -21,6 +21,6 @@ #define __MACH_DMA_H /* This platform uses the common S3C DMA API driver for PL330 */ -#include +#include #endif /* __MACH_DMA_H */ diff --git a/arch/arm/mach-s5pc100/include/mach/dma.h b/arch/arm/mach-s5pc100/include/mach/dma.h index 81209eb1409b..1beae2cca6a3 100644 --- a/arch/arm/mach-s5pc100/include/mach/dma.h +++ b/arch/arm/mach-s5pc100/include/mach/dma.h @@ -21,6 +21,6 @@ #define __MACH_DMA_H /* This platform uses the common S3C DMA API driver for PL330 */ -#include +#include #endif /* __MACH_DMA_H */ diff --git a/arch/arm/mach-s5pv210/include/mach/dma.h b/arch/arm/mach-s5pv210/include/mach/dma.h index 81209eb1409b..1beae2cca6a3 100644 --- a/arch/arm/mach-s5pv210/include/mach/dma.h +++ b/arch/arm/mach-s5pv210/include/mach/dma.h @@ -21,6 +21,6 @@ #define __MACH_DMA_H /* This platform uses the common S3C DMA API driver for PL330 */ -#include +#include #endif /* __MACH_DMA_H */ diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index b3e10659e4b8..e6f01ab86208 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -306,6 +306,15 @@ config S3C_PL330_DMA help S3C DMA API Driver for PL330 DMAC. +config SAMSUNG_DMADEV + bool + select DMADEVICES + select PL330_DMA if (CPU_EXYNOS4210 || CPU_S5PV210 || CPU_S5PC100 || \ + CPU_S5P6450 || CPU_S5P6440) + select ARM_AMBA + help + Use DMA device engine for PL330 DMAC. + comment "Power management" config SAMSUNG_PM_DEBUG diff --git a/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h similarity index 93% rename from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h rename to arch/arm/plat-samsung/include/plat/dma-pl330.h index 810744213120..0a5dade0e85c 100644 --- a/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -8,8 +8,8 @@ * (at your option) any later version. */ -#ifndef __S3C_DMA_PL330_H_ -#define __S3C_DMA_PL330_H_ +#ifndef __DMA_PL330_H_ +#define __DMA_PL330_H_ __FILE__ #define S3C2410_DMAF_AUTOSTART (1 << 0) #define S3C2410_DMAF_CIRCULAR (1 << 1) @@ -20,7 +20,7 @@ * For the sake of consistency across client drivers, * We keep the channel names unchanged and only add * missing peripherals are added. - * Order is not important since S3C PL330 API driver + * Order is not important since DMA PL330 API driver * use these just as IDs. */ enum dma_ch { @@ -95,4 +95,4 @@ static inline bool s3c_dma_has_circular(void) #include -#endif /* __S3C_DMA_PL330_H_ */ +#endif /* __DMA_PL330_H_ */ diff --git a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h b/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h index bf5e2a9d408d..64fdf66ff9cf 100644 --- a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h +++ b/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h @@ -12,7 +12,7 @@ #ifndef __S3C_PL330_PDATA_H #define __S3C_PL330_PDATA_H -#include +#include /* * Every PL330 DMAC has max 32 peripheral interfaces, From c4e1662550a3bd23df7cff4611eff67ba2afe078 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:35 +0900 Subject: [PATCH 0356/1596] ARM: SAMSUNG: Add common DMA operations This patch adds common DMA operations which are used for Samsung DMA drivers. Currently there are two types of DMA driver for Samsung SoCs. The one is S3C-DMA for S3C SoCs and the other is PL330-DMA for S5P SoCs. This patch provides funcion pointers for common DMA operations to DMA client driver like SPI and Audio. It makes DMA client drivers support multi-platform. In addition, this common DMA operations implement the shared actions that are needed for DMA client driver. For example shared actions are filter() function for dma_request_channel() and parameter passing for device_prep_slave_sg(). Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/mach-s3c2410/include/mach/dma.h | 8 +- arch/arm/mach-s3c64xx/include/mach/dma.h | 4 + arch/arm/plat-samsung/Makefile | 6 +- arch/arm/plat-samsung/dma-ops.c | 131 +++++++++++++++++ arch/arm/plat-samsung/include/plat/dma-ops.h | 63 +++++++++ .../arm/plat-samsung/include/plat/dma-pl330.h | 4 + arch/arm/plat-samsung/include/plat/dma.h | 1 + arch/arm/plat-samsung/s3c-dma-ops.c | 133 ++++++++++++++++++ 8 files changed, 347 insertions(+), 3 deletions(-) create mode 100644 arch/arm/plat-samsung/dma-ops.c create mode 100644 arch/arm/plat-samsung/include/plat/dma-ops.h create mode 100644 arch/arm/plat-samsung/s3c-dma-ops.c diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h index b2b2a5bb275e..e61a91f88c52 100644 --- a/arch/arm/mach-s3c2410/include/mach/dma.h +++ b/arch/arm/mach-s3c2410/include/mach/dma.h @@ -13,7 +13,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H __FILE__ -#include #include #define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ @@ -51,6 +50,13 @@ enum dma_ch { DMACH_MAX, /* the end entry */ }; +static inline bool samsung_dma_is_dmadev(void) +{ + return false; +} + +#include + #define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */ /* we have 4 dma channels */ diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 0a5d9268a23e..49c3a53135d4 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -63,6 +63,10 @@ static __inline__ bool s3c_dma_has_circular(void) return true; } +static inline bool samsung_dma_is_dmadev(void) +{ + return false; +} #define S3C2410_DMAF_CIRCULAR (1 << 0) #include diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 853764ba8cc5..e2ee0b8a3763 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -63,9 +63,11 @@ obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o # DMA support -obj-$(CONFIG_S3C_DMA) += dma.o +obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o -obj-$(CONFIG_S3C_PL330_DMA) += s3c-pl330.o +obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o + +obj-$(CONFIG_S3C_PL330_DMA) += s3c-pl330.o s3c-dma-ops.o # PM support diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c new file mode 100644 index 000000000000..6e3d9abc9e2e --- /dev/null +++ b/arch/arm/plat-samsung/dma-ops.c @@ -0,0 +1,131 @@ +/* linux/arch/arm/plat-samsung/dma-ops.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung DMA Operations + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include + +static inline bool pl330_filter(struct dma_chan *chan, void *param) +{ + struct dma_pl330_peri *peri = chan->private; + return peri->peri_id == (unsigned)param; +} + +static unsigned samsung_dmadev_request(enum dma_ch dma_ch, + struct samsung_dma_info *info) +{ + struct dma_chan *chan; + dma_cap_mask_t mask; + struct dma_slave_config slave_config; + + dma_cap_zero(mask); + dma_cap_set(info->cap, mask); + + chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch); + + if (info->direction == DMA_FROM_DEVICE) { + memset(&slave_config, 0, sizeof(struct dma_slave_config)); + slave_config.direction = info->direction; + slave_config.src_addr = info->fifo; + slave_config.src_addr_width = info->width; + slave_config.src_maxburst = 1; + dmaengine_slave_config(chan, &slave_config); + } else if (info->direction == DMA_TO_DEVICE) { + memset(&slave_config, 0, sizeof(struct dma_slave_config)); + slave_config.direction = info->direction; + slave_config.dst_addr = info->fifo; + slave_config.dst_addr_width = info->width; + slave_config.dst_maxburst = 1; + dmaengine_slave_config(chan, &slave_config); + } + + return (unsigned)chan; +} + +static int samsung_dmadev_release(unsigned ch, + struct s3c2410_dma_client *client) +{ + dma_release_channel((struct dma_chan *)ch); + + return 0; +} + +static int samsung_dmadev_prepare(unsigned ch, + struct samsung_dma_prep_info *info) +{ + struct scatterlist sg; + struct dma_chan *chan = (struct dma_chan *)ch; + struct dma_async_tx_descriptor *desc; + + switch (info->cap) { + case DMA_SLAVE: + sg_init_table(&sg, 1); + sg_dma_len(&sg) = info->len; + sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)), + info->len, offset_in_page(info->buf)); + sg_dma_address(&sg) = info->buf; + + desc = chan->device->device_prep_slave_sg(chan, + &sg, 1, info->direction, DMA_PREP_INTERRUPT); + break; + case DMA_CYCLIC: + desc = chan->device->device_prep_dma_cyclic(chan, + info->buf, info->len, info->period, info->direction); + break; + default: + dev_err(&chan->dev->device, "unsupported format\n"); + return -EFAULT; + } + + if (!desc) { + dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); + return -EFAULT; + } + + desc->callback = info->fp; + desc->callback_param = info->fp_param; + + dmaengine_submit((struct dma_async_tx_descriptor *)desc); + + return 0; +} + +static inline int samsung_dmadev_trigger(unsigned ch) +{ + dma_async_issue_pending((struct dma_chan *)ch); + + return 0; +} + +static inline int samsung_dmadev_flush(unsigned ch) +{ + return dmaengine_terminate_all((struct dma_chan *)ch); +} + +struct samsung_dma_ops dmadev_ops = { + .request = samsung_dmadev_request, + .release = samsung_dmadev_release, + .prepare = samsung_dmadev_prepare, + .trigger = samsung_dmadev_trigger, + .started = NULL, + .flush = samsung_dmadev_flush, + .stop = samsung_dmadev_flush, +}; + +void *samsung_dmadev_get_ops(void) +{ + return &dmadev_ops; +} +EXPORT_SYMBOL(samsung_dmadev_get_ops); diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h new file mode 100644 index 000000000000..4c1a363526cf --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma-ops.h @@ -0,0 +1,63 @@ +/* arch/arm/plat-samsung/include/plat/dma-ops.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung DMA support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SAMSUNG_DMA_OPS_H_ +#define __SAMSUNG_DMA_OPS_H_ __FILE__ + +#include + +struct samsung_dma_prep_info { + enum dma_transaction_type cap; + enum dma_data_direction direction; + dma_addr_t buf; + unsigned long period; + unsigned long len; + void (*fp)(void *data); + void *fp_param; +}; + +struct samsung_dma_info { + enum dma_transaction_type cap; + enum dma_data_direction direction; + enum dma_slave_buswidth width; + dma_addr_t fifo; + struct s3c2410_dma_client *client; +}; + +struct samsung_dma_ops { + unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info); + int (*release)(unsigned ch, struct s3c2410_dma_client *client); + int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info); + int (*trigger)(unsigned ch); + int (*started)(unsigned ch); + int (*flush)(unsigned ch); + int (*stop)(unsigned ch); +}; + +extern void *samsung_dmadev_get_ops(void); +extern void *s3c_dma_get_ops(void); + +static inline void *__samsung_dma_get_ops(void) +{ + if (samsung_dma_is_dmadev()) + return samsung_dmadev_get_ops(); + else + return s3c_dma_get_ops(); +} + +/* + * samsung_dma_get_ops + * get the set of samsung dma operations + */ +#define samsung_dma_get_ops() __samsung_dma_get_ops() + +#endif /* __SAMSUNG_DMA_OPS_H_ */ diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h index 0a5dade0e85c..2916920034f0 100644 --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -93,6 +93,10 @@ static inline bool s3c_dma_has_circular(void) return true; } +static inline bool samsung_dma_is_dmadev(void) +{ + return true; +} #include #endif /* __DMA_PL330_H_ */ diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h index 8c273b7a6f56..361076060744 100644 --- a/arch/arm/plat-samsung/include/plat/dma.h +++ b/arch/arm/plat-samsung/include/plat/dma.h @@ -126,3 +126,4 @@ extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn); extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); +#include diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c new file mode 100644 index 000000000000..33ab3241268d --- /dev/null +++ b/arch/arm/plat-samsung/s3c-dma-ops.c @@ -0,0 +1,133 @@ +/* linux/arch/arm/plat-samsung/s3c-dma-ops.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung S3C-DMA Operations + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include + +struct cb_data { + void (*fp) (void *); + void *fp_param; + unsigned ch; + struct list_head node; +}; + +static LIST_HEAD(dma_list); + +static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param, + int size, enum s3c2410_dma_buffresult res) +{ + struct cb_data *data = param; + + data->fp(data->fp_param); +} + +static unsigned s3c_dma_request(enum dma_ch dma_ch, + struct samsung_dma_info *info) +{ + struct cb_data *data; + + if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) { + s3c2410_dma_free(dma_ch, info->client); + return 0; + } + + data = kzalloc(sizeof(struct cb_data), GFP_KERNEL); + data->ch = dma_ch; + list_add_tail(&data->node, &dma_list); + + if (info->direction == DMA_FROM_DEVICE) + s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW, info->fifo); + else + s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM, info->fifo); + + if (info->cap == DMA_CYCLIC) + s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR); + + s3c2410_dma_config(dma_ch, info->width); + + return (unsigned)dma_ch; +} + +static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client) +{ + struct cb_data *data; + + list_for_each_entry(data, &dma_list, node) + if (data->ch == ch) + break; + list_del(&data->node); + + s3c2410_dma_free(ch, client); + kfree(data); + + return 0; +} + +static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info) +{ + struct cb_data *data; + int len = (info->cap == DMA_CYCLIC) ? info->period : info->len; + + list_for_each_entry(data, &dma_list, node) + if (data->ch == ch) + break; + + if (!data->fp) { + s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb); + data->fp = info->fp; + data->fp_param = info->fp_param; + } + + s3c2410_dma_enqueue(ch, (void *)data, info->buf, len); + + return 0; +} + +static inline int s3c_dma_trigger(unsigned ch) +{ + return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START); +} + +static inline int s3c_dma_started(unsigned ch) +{ + return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED); +} + +static inline int s3c_dma_flush(unsigned ch) +{ + return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH); +} + +static inline int s3c_dma_stop(unsigned ch) +{ + return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP); +} + +static struct samsung_dma_ops s3c_dma_ops = { + .request = s3c_dma_request, + .release = s3c_dma_release, + .prepare = s3c_dma_prepare, + .trigger = s3c_dma_trigger, + .started = s3c_dma_started, + .flush = s3c_dma_flush, + .stop = s3c_dma_stop, +}; + +void *s3c_dma_get_ops(void) +{ + return &s3c_dma_ops; +} +EXPORT_SYMBOL(s3c_dma_get_ops); From bf856fbb5e104ab9afd366baa0d744dd8cfa074d Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:36 +0900 Subject: [PATCH 0357/1596] ARM: EXYNOS4: Use generic DMA PL330 driver This patch makes Samsung EXYNOS4 to use DMA PL330 driver on DMADEVICE. The EXYNOS4 uses DMA generic APIs instead of SAMSUNG specific S3C-PL330 APIs. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/mach-exynos4/Kconfig | 2 +- arch/arm/mach-exynos4/clock.c | 11 +- arch/arm/mach-exynos4/dma.c | 299 +++++++++++++++++++++------------- 3 files changed, 198 insertions(+), 114 deletions(-) diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 0c77ab99fa16..9f00cf3450df 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -11,7 +11,7 @@ if ARCH_EXYNOS4 config CPU_EXYNOS4210 bool - select S3C_PL330_DMA + select SAMSUNG_DMADEV help Enable EXYNOS4210 CPU support diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c index 851dea018578..fee2dd8791d0 100644 --- a/arch/arm/mach-exynos4/clock.c +++ b/arch/arm/mach-exynos4/clock.c @@ -43,6 +43,11 @@ static struct clk clk_sclk_usbphy1 = { .name = "sclk_usbphy1", }; +static struct clk dummy_apb_pclk = { + .name = "apb_pclk", + .id = -1, +}; + static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable); @@ -454,12 +459,12 @@ static struct clk init_clocks_off[] = { .enable = exynos4_clk_ip_fsys_ctrl, .ctrlbit = (1 << 10), }, { - .name = "pdma", + .name = "dma", .devname = "s3c-pl330.0", .enable = exynos4_clk_ip_fsys_ctrl, .ctrlbit = (1 << 0), }, { - .name = "pdma", + .name = "dma", .devname = "s3c-pl330.1", .enable = exynos4_clk_ip_fsys_ctrl, .ctrlbit = (1 << 1), @@ -1210,5 +1215,7 @@ void __init exynos4_register_clocks(void) s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + s3c24xx_register_clock(&dummy_apb_pclk); + s3c_pwmclk_init(); } diff --git a/arch/arm/mach-exynos4/dma.c b/arch/arm/mach-exynos4/dma.c index 564bb530f332..d57d66255021 100644 --- a/arch/arm/mach-exynos4/dma.c +++ b/arch/arm/mach-exynos4/dma.c @@ -21,151 +21,228 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include +#include +#include +#include #include #include #include #include - -#include +#include static u64 dma_dmamask = DMA_BIT_MASK(32); -static struct resource exynos4_pdma0_resource[] = { - [0] = { - .start = EXYNOS4_PA_PDMA0, - .end = EXYNOS4_PA_PDMA0 + SZ_4K, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_PDMA0, - .end = IRQ_PDMA0, - .flags = IORESOURCE_IRQ, +struct dma_pl330_peri pdma0_peri[28] = { + { + .peri_id = (u8)DMACH_PCM0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_MSM_REQ0, + }, { + .peri_id = (u8)DMACH_MSM_REQ2, + }, { + .peri_id = (u8)DMACH_SPI0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0S_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART4_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART4_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SLIMBUS0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SLIMBUS0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SLIMBUS2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SLIMBUS2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SLIMBUS4_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SLIMBUS4_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_AC97_MICIN, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_AC97_PCMIN, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_AC97_PCMOUT, + .rqtype = MEMTODEV, }, }; -static struct s3c_pl330_platdata exynos4_pdma0_pdata = { - .peri = { - [0] = DMACH_PCM0_RX, - [1] = DMACH_PCM0_TX, - [2] = DMACH_PCM2_RX, - [3] = DMACH_PCM2_TX, - [4] = DMACH_MSM_REQ0, - [5] = DMACH_MSM_REQ2, - [6] = DMACH_SPI0_RX, - [7] = DMACH_SPI0_TX, - [8] = DMACH_SPI2_RX, - [9] = DMACH_SPI2_TX, - [10] = DMACH_I2S0S_TX, - [11] = DMACH_I2S0_RX, - [12] = DMACH_I2S0_TX, - [13] = DMACH_I2S2_RX, - [14] = DMACH_I2S2_TX, - [15] = DMACH_UART0_RX, - [16] = DMACH_UART0_TX, - [17] = DMACH_UART2_RX, - [18] = DMACH_UART2_TX, - [19] = DMACH_UART4_RX, - [20] = DMACH_UART4_TX, - [21] = DMACH_SLIMBUS0_RX, - [22] = DMACH_SLIMBUS0_TX, - [23] = DMACH_SLIMBUS2_RX, - [24] = DMACH_SLIMBUS2_TX, - [25] = DMACH_SLIMBUS4_RX, - [26] = DMACH_SLIMBUS4_TX, - [27] = DMACH_AC97_MICIN, - [28] = DMACH_AC97_PCMIN, - [29] = DMACH_AC97_PCMOUT, - [30] = DMACH_MAX, - [31] = DMACH_MAX, - }, +struct dma_pl330_platdata exynos4_pdma0_pdata = { + .nr_valid_peri = ARRAY_SIZE(pdma0_peri), + .peri = pdma0_peri, }; -static struct platform_device exynos4_device_pdma0 = { - .name = "s3c-pl330", - .id = 0, - .num_resources = ARRAY_SIZE(exynos4_pdma0_resource), - .resource = exynos4_pdma0_resource, - .dev = { +struct amba_device exynos4_device_pdma0 = { + .dev = { + .init_name = "dma-pl330.0", .dma_mask = &dma_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &exynos4_pdma0_pdata, }, + .res = { + .start = EXYNOS4_PA_PDMA0, + .end = EXYNOS4_PA_PDMA0 + SZ_4K, + .flags = IORESOURCE_MEM, + }, + .irq = {IRQ_PDMA0, NO_IRQ}, + .periphid = 0x00041330, }; -static struct resource exynos4_pdma1_resource[] = { - [0] = { - .start = EXYNOS4_PA_PDMA1, - .end = EXYNOS4_PA_PDMA1 + SZ_4K, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_PDMA1, - .end = IRQ_PDMA1, - .flags = IORESOURCE_IRQ, +struct dma_pl330_peri pdma1_peri[25] = { + { + .peri_id = (u8)DMACH_PCM0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_MSM_REQ1, + }, { + .peri_id = (u8)DMACH_MSM_REQ3, + }, { + .peri_id = (u8)DMACH_SPI1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0S_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART3_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART3_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SLIMBUS1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SLIMBUS1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SLIMBUS3_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SLIMBUS3_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SLIMBUS5_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SLIMBUS5_TX, + .rqtype = MEMTODEV, }, }; -static struct s3c_pl330_platdata exynos4_pdma1_pdata = { - .peri = { - [0] = DMACH_PCM0_RX, - [1] = DMACH_PCM0_TX, - [2] = DMACH_PCM1_RX, - [3] = DMACH_PCM1_TX, - [4] = DMACH_MSM_REQ1, - [5] = DMACH_MSM_REQ3, - [6] = DMACH_SPI1_RX, - [7] = DMACH_SPI1_TX, - [8] = DMACH_I2S0S_TX, - [9] = DMACH_I2S0_RX, - [10] = DMACH_I2S0_TX, - [11] = DMACH_I2S1_RX, - [12] = DMACH_I2S1_TX, - [13] = DMACH_UART0_RX, - [14] = DMACH_UART0_TX, - [15] = DMACH_UART1_RX, - [16] = DMACH_UART1_TX, - [17] = DMACH_UART3_RX, - [18] = DMACH_UART3_TX, - [19] = DMACH_SLIMBUS1_RX, - [20] = DMACH_SLIMBUS1_TX, - [21] = DMACH_SLIMBUS3_RX, - [22] = DMACH_SLIMBUS3_TX, - [23] = DMACH_SLIMBUS5_RX, - [24] = DMACH_SLIMBUS5_TX, - [25] = DMACH_SLIMBUS0AUX_RX, - [26] = DMACH_SLIMBUS0AUX_TX, - [27] = DMACH_SPDIF, - [28] = DMACH_MAX, - [29] = DMACH_MAX, - [30] = DMACH_MAX, - [31] = DMACH_MAX, - }, +struct dma_pl330_platdata exynos4_pdma1_pdata = { + .nr_valid_peri = ARRAY_SIZE(pdma1_peri), + .peri = pdma1_peri, }; -static struct platform_device exynos4_device_pdma1 = { - .name = "s3c-pl330", - .id = 1, - .num_resources = ARRAY_SIZE(exynos4_pdma1_resource), - .resource = exynos4_pdma1_resource, - .dev = { +struct amba_device exynos4_device_pdma1 = { + .dev = { + .init_name = "dma-pl330.1", .dma_mask = &dma_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &exynos4_pdma1_pdata, }, -}; - -static struct platform_device *exynos4_dmacs[] __initdata = { - &exynos4_device_pdma0, - &exynos4_device_pdma1, + .res = { + .start = EXYNOS4_PA_PDMA1, + .end = EXYNOS4_PA_PDMA1 + SZ_4K, + .flags = IORESOURCE_MEM, + }, + .irq = {IRQ_PDMA1, NO_IRQ}, + .periphid = 0x00041330, }; static int __init exynos4_dma_init(void) { - platform_add_devices(exynos4_dmacs, ARRAY_SIZE(exynos4_dmacs)); + amba_device_register(&exynos4_device_pdma0, &iomem_resource); return 0; } From dafc954304ad3a471c82e7aad15b26f6be264560 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:37 +0900 Subject: [PATCH 0358/1596] ARM: S5PV210: Use generic DMA PL330 driver This patch makes Samsung S5PV210 to use DMA PL330 driver on DMADEVICE. The S5PV210 uses DMA generic APIs instead of SAMSUNG specific S3C-PL330 APIs. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/mach-s5pv210/Kconfig | 2 +- arch/arm/mach-s5pv210/clock.c | 10 +- arch/arm/mach-s5pv210/dma.c | 316 +++++++++++++++-------- arch/arm/mach-s5pv210/include/mach/dma.h | 2 +- 4 files changed, 214 insertions(+), 116 deletions(-) diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig index 69dd87cd8e22..d960090e4656 100644 --- a/arch/arm/mach-s5pv210/Kconfig +++ b/arch/arm/mach-s5pv210/Kconfig @@ -11,7 +11,7 @@ if ARCH_S5PV210 config CPU_S5PV210 bool - select S3C_PL330_DMA + select SAMSUNG_DMADEV select S5P_EXT_INT select S5P_HRT select S5PV210_PM if PM diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c index 52a8e607bcc2..d35726a6faea 100644 --- a/arch/arm/mach-s5pv210/clock.c +++ b/arch/arm/mach-s5pv210/clock.c @@ -203,6 +203,11 @@ static struct clk clk_pcmcdclk2 = { .name = "pcmcdclk", }; +static struct clk dummy_apb_pclk = { + .name = "apb_pclk", + .id = -1, +}; + static struct clk *clkset_vpllsrc_list[] = { [0] = &clk_fin_vpll, [1] = &clk_sclk_hdmi27m, @@ -289,13 +294,13 @@ static struct clk_ops clk_fout_apll_ops = { static struct clk init_clocks_off[] = { { - .name = "pdma", + .name = "dma", .devname = "s3c-pl330.0", .parent = &clk_hclk_psys.clk, .enable = s5pv210_clk_ip0_ctrl, .ctrlbit = (1 << 3), }, { - .name = "pdma", + .name = "dma", .devname = "s3c-pl330.1", .parent = &clk_hclk_psys.clk, .enable = s5pv210_clk_ip0_ctrl, @@ -1161,5 +1166,6 @@ void __init s5pv210_register_clocks(void) s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + s3c24xx_register_clock(&dummy_apb_pclk); s3c_pwmclk_init(); } diff --git a/arch/arm/mach-s5pv210/dma.c b/arch/arm/mach-s5pv210/dma.c index 497d3439a142..f79d0b06cbf9 100644 --- a/arch/arm/mach-s5pv210/dma.c +++ b/arch/arm/mach-s5pv210/dma.c @@ -1,4 +1,8 @@ -/* +/* linux/arch/arm/mach-s5pv210/dma.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * * Copyright (C) 2010 Samsung Electronics Co. Ltd. * Jaswinder Singh * @@ -17,151 +21,239 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include +#include +#include +#include #include #include #include #include - -#include +#include static u64 dma_dmamask = DMA_BIT_MASK(32); -static struct resource s5pv210_pdma0_resource[] = { - [0] = { - .start = S5PV210_PA_PDMA0, - .end = S5PV210_PA_PDMA0 + SZ_4K, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_PDMA0, - .end = IRQ_PDMA0, - .flags = IORESOURCE_IRQ, +struct dma_pl330_peri pdma0_peri[28] = { + { + .peri_id = (u8)DMACH_UART0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART3_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART3_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = DMACH_MAX, + }, { + .peri_id = (u8)DMACH_I2S0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0S_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_SPI0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_AC97_MICIN, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_AC97_PCMIN, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_AC97_PCMOUT, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_PWM, + }, { + .peri_id = (u8)DMACH_SPDIF, + .rqtype = MEMTODEV, }, }; -static struct s3c_pl330_platdata s5pv210_pdma0_pdata = { - .peri = { - [0] = DMACH_UART0_RX, - [1] = DMACH_UART0_TX, - [2] = DMACH_UART1_RX, - [3] = DMACH_UART1_TX, - [4] = DMACH_UART2_RX, - [5] = DMACH_UART2_TX, - [6] = DMACH_UART3_RX, - [7] = DMACH_UART3_TX, - [8] = DMACH_MAX, - [9] = DMACH_I2S0_RX, - [10] = DMACH_I2S0_TX, - [11] = DMACH_I2S0S_TX, - [12] = DMACH_I2S1_RX, - [13] = DMACH_I2S1_TX, - [14] = DMACH_MAX, - [15] = DMACH_MAX, - [16] = DMACH_SPI0_RX, - [17] = DMACH_SPI0_TX, - [18] = DMACH_SPI1_RX, - [19] = DMACH_SPI1_TX, - [20] = DMACH_MAX, - [21] = DMACH_MAX, - [22] = DMACH_AC97_MICIN, - [23] = DMACH_AC97_PCMIN, - [24] = DMACH_AC97_PCMOUT, - [25] = DMACH_MAX, - [26] = DMACH_PWM, - [27] = DMACH_SPDIF, - [28] = DMACH_MAX, - [29] = DMACH_MAX, - [30] = DMACH_MAX, - [31] = DMACH_MAX, - }, +struct dma_pl330_platdata s5pv210_pdma0_pdata = { + .nr_valid_peri = ARRAY_SIZE(pdma0_peri), + .peri = pdma0_peri, }; -static struct platform_device s5pv210_device_pdma0 = { - .name = "s3c-pl330", - .id = 0, - .num_resources = ARRAY_SIZE(s5pv210_pdma0_resource), - .resource = s5pv210_pdma0_resource, - .dev = { +struct amba_device s5pv210_device_pdma0 = { + .dev = { + .init_name = "dma-pl330.0", .dma_mask = &dma_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &s5pv210_pdma0_pdata, }, -}; - -static struct resource s5pv210_pdma1_resource[] = { - [0] = { - .start = S5PV210_PA_PDMA1, - .end = S5PV210_PA_PDMA1 + SZ_4K, + .res = { + .start = S5PV210_PA_PDMA0, + .end = S5PV210_PA_PDMA0 + SZ_4K, .flags = IORESOURCE_MEM, }, - [1] = { - .start = IRQ_PDMA1, - .end = IRQ_PDMA1, - .flags = IORESOURCE_IRQ, - }, + .irq = {IRQ_PDMA0, NO_IRQ}, + .periphid = 0x00041330, }; -static struct s3c_pl330_platdata s5pv210_pdma1_pdata = { - .peri = { - [0] = DMACH_UART0_RX, - [1] = DMACH_UART0_TX, - [2] = DMACH_UART1_RX, - [3] = DMACH_UART1_TX, - [4] = DMACH_UART2_RX, - [5] = DMACH_UART2_TX, - [6] = DMACH_UART3_RX, - [7] = DMACH_UART3_TX, - [8] = DMACH_MAX, - [9] = DMACH_I2S0_RX, - [10] = DMACH_I2S0_TX, - [11] = DMACH_I2S0S_TX, - [12] = DMACH_I2S1_RX, - [13] = DMACH_I2S1_TX, - [14] = DMACH_I2S2_RX, - [15] = DMACH_I2S2_TX, - [16] = DMACH_SPI0_RX, - [17] = DMACH_SPI0_TX, - [18] = DMACH_SPI1_RX, - [19] = DMACH_SPI1_TX, - [20] = DMACH_MAX, - [21] = DMACH_MAX, - [22] = DMACH_PCM0_RX, - [23] = DMACH_PCM0_TX, - [24] = DMACH_PCM1_RX, - [25] = DMACH_PCM1_TX, - [26] = DMACH_MSM_REQ0, - [27] = DMACH_MSM_REQ1, - [28] = DMACH_MSM_REQ2, - [29] = DMACH_MSM_REQ3, - [30] = DMACH_PCM2_RX, - [31] = DMACH_PCM2_TX, +struct dma_pl330_peri pdma1_peri[32] = { + { + .peri_id = (u8)DMACH_UART0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART3_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART3_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = DMACH_MAX, + }, { + .peri_id = (u8)DMACH_I2S0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0S_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_PCM0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_MSM_REQ0, + }, { + .peri_id = (u8)DMACH_MSM_REQ1, + }, { + .peri_id = (u8)DMACH_MSM_REQ2, + }, { + .peri_id = (u8)DMACH_MSM_REQ3, + }, { + .peri_id = (u8)DMACH_PCM2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM2_TX, + .rqtype = MEMTODEV, }, }; -static struct platform_device s5pv210_device_pdma1 = { - .name = "s3c-pl330", - .id = 1, - .num_resources = ARRAY_SIZE(s5pv210_pdma1_resource), - .resource = s5pv210_pdma1_resource, - .dev = { +struct dma_pl330_platdata s5pv210_pdma1_pdata = { + .nr_valid_peri = ARRAY_SIZE(pdma1_peri), + .peri = pdma1_peri, +}; + +struct amba_device s5pv210_device_pdma1 = { + .dev = { + .init_name = "dma-pl330.1", .dma_mask = &dma_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &s5pv210_pdma1_pdata, }, -}; - -static struct platform_device *s5pv210_dmacs[] __initdata = { - &s5pv210_device_pdma0, - &s5pv210_device_pdma1, + .res = { + .start = S5PV210_PA_PDMA1, + .end = S5PV210_PA_PDMA1 + SZ_4K, + .flags = IORESOURCE_MEM, + }, + .irq = {IRQ_PDMA1, NO_IRQ}, + .periphid = 0x00041330, }; static int __init s5pv210_dma_init(void) { - platform_add_devices(s5pv210_dmacs, ARRAY_SIZE(s5pv210_dmacs)); + amba_device_register(&s5pv210_device_pdma0, &iomem_resource); return 0; } diff --git a/arch/arm/mach-s5pv210/include/mach/dma.h b/arch/arm/mach-s5pv210/include/mach/dma.h index 1beae2cca6a3..201842a3769e 100644 --- a/arch/arm/mach-s5pv210/include/mach/dma.h +++ b/arch/arm/mach-s5pv210/include/mach/dma.h @@ -20,7 +20,7 @@ #ifndef __MACH_DMA_H #define __MACH_DMA_H -/* This platform uses the common S3C DMA API driver for PL330 */ +/* This platform uses the common DMA API driver for PL330 */ #include #endif /* __MACH_DMA_H */ From a422bd0f6d50bcb9c529d890bde70295915bb3e9 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:38 +0900 Subject: [PATCH 0359/1596] ARM: S5PC100: Use generic DMA PL330 driver This patch makes Samsung S5PC100 to use DMA PL330 driver on DMADEVICE. The S5PC100 uses DMA generic APIs instead of SAMSUNG specific S3C-PL330 APIs. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/mach-s5pc100/Kconfig | 2 +- arch/arm/mach-s5pc100/clock.c | 11 +- arch/arm/mach-s5pc100/dma.c | 323 +++++++++++++++-------- arch/arm/mach-s5pc100/include/mach/dma.h | 2 +- 4 files changed, 222 insertions(+), 116 deletions(-) diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig index e8a33c4b054c..e538a4c67e9c 100644 --- a/arch/arm/mach-s5pc100/Kconfig +++ b/arch/arm/mach-s5pc100/Kconfig @@ -10,7 +10,7 @@ if ARCH_S5PC100 config CPU_S5PC100 bool select S5P_EXT_INT - select S3C_PL330_DMA + select SAMSUNG_DMADEV help Enable S5PC100 CPU support diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c index ff5cbb30de5b..6527c05c5fa1 100644 --- a/arch/arm/mach-s5pc100/clock.c +++ b/arch/arm/mach-s5pc100/clock.c @@ -33,6 +33,11 @@ static struct clk s5p_clk_otgphy = { .name = "otg_phy", }; +static struct clk dummy_apb_pclk = { + .name = "apb_pclk", + .id = -1, +}; + static struct clk *clk_src_mout_href_list[] = { [0] = &s5p_clk_27m, [1] = &clk_fin_hpll, @@ -454,13 +459,13 @@ static struct clk init_clocks_off[] = { .enable = s5pc100_d1_0_ctrl, .ctrlbit = (1 << 2), }, { - .name = "pdma", + .name = "dma", .devname = "s3c-pl330.1", .parent = &clk_div_d1_bus.clk, .enable = s5pc100_d1_0_ctrl, .ctrlbit = (1 << 1), }, { - .name = "pdma", + .name = "dma", .devname = "s3c-pl330.0", .parent = &clk_div_d1_bus.clk, .enable = s5pc100_d1_0_ctrl, @@ -1276,5 +1281,7 @@ void __init s5pc100_register_clocks(void) s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + s3c24xx_register_clock(&dummy_apb_pclk); + s3c_pwmclk_init(); } diff --git a/arch/arm/mach-s5pc100/dma.c b/arch/arm/mach-s5pc100/dma.c index bf4cd0fb97c6..ef803e92d35d 100644 --- a/arch/arm/mach-s5pc100/dma.c +++ b/arch/arm/mach-s5pc100/dma.c @@ -1,4 +1,8 @@ -/* +/* linux/arch/arm/mach-s5pc100/dma.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * * Copyright (C) 2010 Samsung Electronics Co. Ltd. * Jaswinder Singh * @@ -17,150 +21,245 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include +#include +#include +#include #include +#include #include #include - -#include +#include static u64 dma_dmamask = DMA_BIT_MASK(32); -static struct resource s5pc100_pdma0_resource[] = { - [0] = { - .start = S5PC100_PA_PDMA0, - .end = S5PC100_PA_PDMA0 + SZ_4K, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_PDMA0, - .end = IRQ_PDMA0, - .flags = IORESOURCE_IRQ, +struct dma_pl330_peri pdma0_peri[30] = { + { + .peri_id = (u8)DMACH_UART0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART3_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART3_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = DMACH_IRDA, + }, { + .peri_id = (u8)DMACH_I2S0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0S_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_AC97_MICIN, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_AC97_PCMIN, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_AC97_PCMOUT, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_EXTERNAL, + }, { + .peri_id = (u8)DMACH_PWM, + }, { + .peri_id = (u8)DMACH_SPDIF, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_HSI_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_HSI_TX, + .rqtype = MEMTODEV, }, }; -static struct s3c_pl330_platdata s5pc100_pdma0_pdata = { - .peri = { - [0] = DMACH_UART0_RX, - [1] = DMACH_UART0_TX, - [2] = DMACH_UART1_RX, - [3] = DMACH_UART1_TX, - [4] = DMACH_UART2_RX, - [5] = DMACH_UART2_TX, - [6] = DMACH_UART3_RX, - [7] = DMACH_UART3_TX, - [8] = DMACH_IRDA, - [9] = DMACH_I2S0_RX, - [10] = DMACH_I2S0_TX, - [11] = DMACH_I2S0S_TX, - [12] = DMACH_I2S1_RX, - [13] = DMACH_I2S1_TX, - [14] = DMACH_I2S2_RX, - [15] = DMACH_I2S2_TX, - [16] = DMACH_SPI0_RX, - [17] = DMACH_SPI0_TX, - [18] = DMACH_SPI1_RX, - [19] = DMACH_SPI1_TX, - [20] = DMACH_SPI2_RX, - [21] = DMACH_SPI2_TX, - [22] = DMACH_AC97_MICIN, - [23] = DMACH_AC97_PCMIN, - [24] = DMACH_AC97_PCMOUT, - [25] = DMACH_EXTERNAL, - [26] = DMACH_PWM, - [27] = DMACH_SPDIF, - [28] = DMACH_HSI_RX, - [29] = DMACH_HSI_TX, - [30] = DMACH_MAX, - [31] = DMACH_MAX, - }, +struct dma_pl330_platdata s5pc100_pdma0_pdata = { + .nr_valid_peri = ARRAY_SIZE(pdma0_peri), + .peri = pdma0_peri, }; -static struct platform_device s5pc100_device_pdma0 = { - .name = "s3c-pl330", - .id = 0, - .num_resources = ARRAY_SIZE(s5pc100_pdma0_resource), - .resource = s5pc100_pdma0_resource, - .dev = { +struct amba_device s5pc100_device_pdma0 = { + .dev = { + .init_name = "dma-pl330.0", .dma_mask = &dma_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &s5pc100_pdma0_pdata, }, -}; - -static struct resource s5pc100_pdma1_resource[] = { - [0] = { - .start = S5PC100_PA_PDMA1, - .end = S5PC100_PA_PDMA1 + SZ_4K, + .res = { + .start = S5PC100_PA_PDMA0, + .end = S5PC100_PA_PDMA0 + SZ_4K, .flags = IORESOURCE_MEM, }, - [1] = { - .start = IRQ_PDMA1, - .end = IRQ_PDMA1, - .flags = IORESOURCE_IRQ, - }, + .irq = {IRQ_PDMA0, NO_IRQ}, + .periphid = 0x00041330, }; -static struct s3c_pl330_platdata s5pc100_pdma1_pdata = { - .peri = { - [0] = DMACH_UART0_RX, - [1] = DMACH_UART0_TX, - [2] = DMACH_UART1_RX, - [3] = DMACH_UART1_TX, - [4] = DMACH_UART2_RX, - [5] = DMACH_UART2_TX, - [6] = DMACH_UART3_RX, - [7] = DMACH_UART3_TX, - [8] = DMACH_IRDA, - [9] = DMACH_I2S0_RX, - [10] = DMACH_I2S0_TX, - [11] = DMACH_I2S0S_TX, - [12] = DMACH_I2S1_RX, - [13] = DMACH_I2S1_TX, - [14] = DMACH_I2S2_RX, - [15] = DMACH_I2S2_TX, - [16] = DMACH_SPI0_RX, - [17] = DMACH_SPI0_TX, - [18] = DMACH_SPI1_RX, - [19] = DMACH_SPI1_TX, - [20] = DMACH_SPI2_RX, - [21] = DMACH_SPI2_TX, - [22] = DMACH_PCM0_RX, - [23] = DMACH_PCM0_TX, - [24] = DMACH_PCM1_RX, - [25] = DMACH_PCM1_TX, - [26] = DMACH_MSM_REQ0, - [27] = DMACH_MSM_REQ1, - [28] = DMACH_MSM_REQ2, - [29] = DMACH_MSM_REQ3, - [30] = DMACH_MAX, - [31] = DMACH_MAX, +struct dma_pl330_peri pdma1_peri[30] = { + { + .peri_id = (u8)DMACH_UART0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART3_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART3_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = DMACH_IRDA, + }, { + .peri_id = (u8)DMACH_I2S0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0S_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_MSM_REQ0, + }, { + .peri_id = (u8)DMACH_MSM_REQ1, + }, { + .peri_id = (u8)DMACH_MSM_REQ2, + }, { + .peri_id = (u8)DMACH_MSM_REQ3, }, }; -static struct platform_device s5pc100_device_pdma1 = { - .name = "s3c-pl330", - .id = 1, - .num_resources = ARRAY_SIZE(s5pc100_pdma1_resource), - .resource = s5pc100_pdma1_resource, - .dev = { +struct dma_pl330_platdata s5pc100_pdma1_pdata = { + .nr_valid_peri = ARRAY_SIZE(pdma1_peri), + .peri = pdma1_peri, +}; + +struct amba_device s5pc100_device_pdma1 = { + .dev = { + .init_name = "dma-pl330.1", .dma_mask = &dma_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &s5pc100_pdma1_pdata, }, -}; - -static struct platform_device *s5pc100_dmacs[] __initdata = { - &s5pc100_device_pdma0, - &s5pc100_device_pdma1, + .res = { + .start = S5PC100_PA_PDMA1, + .end = S5PC100_PA_PDMA1 + SZ_4K, + .flags = IORESOURCE_MEM, + }, + .irq = {IRQ_PDMA1, NO_IRQ}, + .periphid = 0x00041330, }; static int __init s5pc100_dma_init(void) { - platform_add_devices(s5pc100_dmacs, ARRAY_SIZE(s5pc100_dmacs)); + amba_device_register(&s5pc100_device_pdma0, &iomem_resource); return 0; } diff --git a/arch/arm/mach-s5pc100/include/mach/dma.h b/arch/arm/mach-s5pc100/include/mach/dma.h index 1beae2cca6a3..201842a3769e 100644 --- a/arch/arm/mach-s5pc100/include/mach/dma.h +++ b/arch/arm/mach-s5pc100/include/mach/dma.h @@ -20,7 +20,7 @@ #ifndef __MACH_DMA_H #define __MACH_DMA_H -/* This platform uses the common S3C DMA API driver for PL330 */ +/* This platform uses the common DMA API driver for PL330 */ #include #endif /* __MACH_DMA_H */ From 3091e61173211de3fbd9bcb99ddc33333377fcb7 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:39 +0900 Subject: [PATCH 0360/1596] ARM: S5P64X0: Use generic DMA PL330 driver This patch makes Samsung S5P64X0 to use DMA PL330 driver on DMADEVICE. The S5P64X0 uses DMA generic APIs instead of SAMSUNG specific S3C-PL330 APIs. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/mach-s5p64x0/Kconfig | 4 +- arch/arm/mach-s5p64x0/clock-s5p6440.c | 9 +- arch/arm/mach-s5p64x0/clock-s5p6450.c | 9 +- arch/arm/mach-s5p64x0/dma.c | 273 +++++++++++++++-------- arch/arm/mach-s5p64x0/include/mach/dma.h | 2 +- 5 files changed, 201 insertions(+), 96 deletions(-) diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig index 65c7518dad7f..9527ed24dbff 100644 --- a/arch/arm/mach-s5p64x0/Kconfig +++ b/arch/arm/mach-s5p64x0/Kconfig @@ -9,14 +9,14 @@ if ARCH_S5P64X0 config CPU_S5P6440 bool - select S3C_PL330_DMA + select SAMSUNG_DMADEV select S5P_HRT help Enable S5P6440 CPU support config CPU_S5P6450 bool - select S3C_PL330_DMA + select SAMSUNG_DMADEV select S5P_HRT help Enable S5P6450 CPU support diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c index 0e9cd3092dd2..c1f548f69a0d 100644 --- a/arch/arm/mach-s5p64x0/clock-s5p6440.c +++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c @@ -146,7 +146,7 @@ static struct clk init_clocks_off[] = { .enable = s5p64x0_hclk0_ctrl, .ctrlbit = (1 << 8), }, { - .name = "pdma", + .name = "dma", .parent = &clk_hclk_low.clk, .enable = s5p64x0_hclk0_ctrl, .ctrlbit = (1 << 12), @@ -499,6 +499,11 @@ static struct clksrc_clk *sysclks[] = { &clk_pclk_low, }; +static struct clk dummy_apb_pclk = { + .name = "apb_pclk", + .id = -1, +}; + void __init_or_cpufreq s5p6440_setup_clocks(void) { struct clk *xtal_clk; @@ -581,5 +586,7 @@ void __init s5p6440_register_clocks(void) s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + s3c24xx_register_clock(&dummy_apb_pclk); + s3c_pwmclk_init(); } diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c index d9dc16cde109..3d9b60975570 100644 --- a/arch/arm/mach-s5p64x0/clock-s5p6450.c +++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c @@ -179,7 +179,7 @@ static struct clk init_clocks_off[] = { .enable = s5p64x0_hclk0_ctrl, .ctrlbit = (1 << 3), }, { - .name = "pdma", + .name = "dma", .parent = &clk_hclk_low.clk, .enable = s5p64x0_hclk0_ctrl, .ctrlbit = (1 << 12), @@ -553,6 +553,11 @@ static struct clksrc_clk *sysclks[] = { &clk_sclk_audio0, }; +static struct clk dummy_apb_pclk = { + .name = "apb_pclk", + .id = -1, +}; + void __init_or_cpufreq s5p6450_setup_clocks(void) { struct clk *xtal_clk; @@ -632,5 +637,7 @@ void __init s5p6450_register_clocks(void) s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + s3c24xx_register_clock(&dummy_apb_pclk); + s3c_pwmclk_init(); } diff --git a/arch/arm/mach-s5p64x0/dma.c b/arch/arm/mach-s5p64x0/dma.c index d7ad944b3475..aebf3fcb1ebe 100644 --- a/arch/arm/mach-s5p64x0/dma.c +++ b/arch/arm/mach-s5p64x0/dma.c @@ -21,128 +21,219 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include +#include +#include + +#include #include #include #include +#include #include -#include +#include static u64 dma_dmamask = DMA_BIT_MASK(32); -static struct resource s5p64x0_pdma_resource[] = { - [0] = { - .start = S5P64X0_PA_PDMA, - .end = S5P64X0_PA_PDMA + SZ_4K, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_DMA0, - .end = IRQ_DMA0, - .flags = IORESOURCE_IRQ, +struct dma_pl330_peri s5p6440_pdma_peri[22] = { + { + .peri_id = (u8)DMACH_UART0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART3_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART3_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = DMACH_MAX, + }, { + .peri_id = DMACH_MAX, + }, { + .peri_id = (u8)DMACH_PCM0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_SPI1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI1_RX, + .rqtype = DEVTOMEM, }, }; -static struct s3c_pl330_platdata s5p6440_pdma_pdata = { - .peri = { - [0] = DMACH_UART0_RX, - [1] = DMACH_UART0_TX, - [2] = DMACH_UART1_RX, - [3] = DMACH_UART1_TX, - [4] = DMACH_UART2_RX, - [5] = DMACH_UART2_TX, - [6] = DMACH_UART3_RX, - [7] = DMACH_UART3_TX, - [8] = DMACH_MAX, - [9] = DMACH_MAX, - [10] = DMACH_PCM0_TX, - [11] = DMACH_PCM0_RX, - [12] = DMACH_I2S0_TX, - [13] = DMACH_I2S0_RX, - [14] = DMACH_SPI0_TX, - [15] = DMACH_SPI0_RX, - [16] = DMACH_MAX, - [17] = DMACH_MAX, - [18] = DMACH_MAX, - [19] = DMACH_MAX, - [20] = DMACH_SPI1_TX, - [21] = DMACH_SPI1_RX, - [22] = DMACH_MAX, - [23] = DMACH_MAX, - [24] = DMACH_MAX, - [25] = DMACH_MAX, - [26] = DMACH_MAX, - [27] = DMACH_MAX, - [28] = DMACH_MAX, - [29] = DMACH_PWM, - [30] = DMACH_MAX, - [31] = DMACH_MAX, - }, +struct dma_pl330_platdata s5p6440_pdma_pdata = { + .nr_valid_peri = ARRAY_SIZE(s5p6440_pdma_peri), + .peri = s5p6440_pdma_peri, }; -static struct s3c_pl330_platdata s5p6450_pdma_pdata = { - .peri = { - [0] = DMACH_UART0_RX, - [1] = DMACH_UART0_TX, - [2] = DMACH_UART1_RX, - [3] = DMACH_UART1_TX, - [4] = DMACH_UART2_RX, - [5] = DMACH_UART2_TX, - [6] = DMACH_UART3_RX, - [7] = DMACH_UART3_TX, - [8] = DMACH_UART4_RX, - [9] = DMACH_UART4_TX, - [10] = DMACH_PCM0_TX, - [11] = DMACH_PCM0_RX, - [12] = DMACH_I2S0_TX, - [13] = DMACH_I2S0_RX, - [14] = DMACH_SPI0_TX, - [15] = DMACH_SPI0_RX, - [16] = DMACH_PCM1_TX, - [17] = DMACH_PCM1_RX, - [18] = DMACH_PCM2_TX, - [19] = DMACH_PCM2_RX, - [20] = DMACH_SPI1_TX, - [21] = DMACH_SPI1_RX, - [22] = DMACH_USI_TX, - [23] = DMACH_USI_RX, - [24] = DMACH_MAX, - [25] = DMACH_I2S1_TX, - [26] = DMACH_I2S1_RX, - [27] = DMACH_I2S2_TX, - [28] = DMACH_I2S2_RX, - [29] = DMACH_PWM, - [30] = DMACH_UART5_RX, - [31] = DMACH_UART5_TX, +struct dma_pl330_peri s5p6450_pdma_peri[32] = { + { + .peri_id = (u8)DMACH_UART0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART3_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART3_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_UART4_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART4_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI0_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI0_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PCM2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_PCM2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_SPI1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_SPI1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_USI_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_USI_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_MAX, + }, { + .peri_id = (u8)DMACH_I2S1_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S1_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_I2S2_TX, + .rqtype = MEMTODEV, + }, { + .peri_id = (u8)DMACH_I2S2_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_PWM, + }, { + .peri_id = (u8)DMACH_UART5_RX, + .rqtype = DEVTOMEM, + }, { + .peri_id = (u8)DMACH_UART5_TX, + .rqtype = MEMTODEV, }, }; -static struct platform_device s5p64x0_device_pdma = { - .name = "s3c-pl330", - .id = -1, - .num_resources = ARRAY_SIZE(s5p64x0_pdma_resource), - .resource = s5p64x0_pdma_resource, - .dev = { +struct dma_pl330_platdata s5p6450_pdma_pdata = { + .nr_valid_peri = ARRAY_SIZE(s5p6450_pdma_peri), + .peri = s5p6450_pdma_peri, +}; + +struct amba_device s5p64x0_device_pdma = { + .dev = { + .init_name = "dma-pl330", .dma_mask = &dma_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), }, + .res = { + .start = S5P64X0_PA_PDMA, + .end = S5P64X0_PA_PDMA + SZ_4K, + .flags = IORESOURCE_MEM, + }, + .irq = {IRQ_DMA0, NO_IRQ}, + .periphid = 0x00041330, }; static int __init s5p64x0_dma_init(void) { - unsigned int id; - - id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000; + unsigned int id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000; if (id == 0x50000) s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata; else s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata; - platform_device_register(&s5p64x0_device_pdma); + amba_device_register(&s5p64x0_device_pdma, &iomem_resource); return 0; } diff --git a/arch/arm/mach-s5p64x0/include/mach/dma.h b/arch/arm/mach-s5p64x0/include/mach/dma.h index 1beae2cca6a3..5a622af461d7 100644 --- a/arch/arm/mach-s5p64x0/include/mach/dma.h +++ b/arch/arm/mach-s5p64x0/include/mach/dma.h @@ -20,7 +20,7 @@ #ifndef __MACH_DMA_H #define __MACH_DMA_H -/* This platform uses the common S3C DMA API driver for PL330 */ +/* This platform uses the common common DMA API driver for PL330 */ #include #endif /* __MACH_DMA_H */ From 978ce50dd5cfd93380ded89d61de9d8109ebd814 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:40 +0900 Subject: [PATCH 0361/1596] ARM: SAMSUNG: Remove S3C-PL330-DMA driver Since DMA generic APIs can be used for Samsung DMA now so that the s3c-pl330 which includes Samsung specific DMA APIs can be removed. Signed-off-by: Boojin Kim Cc: Jassi Brar Acked-by: Linus Walleij Acked-by: Vinod Koul Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/plat-samsung/Kconfig | 6 - arch/arm/plat-samsung/Makefile | 2 - .../arm/plat-samsung/include/plat/dma-pl330.h | 10 +- .../include/plat/s3c-pl330-pdata.h | 32 - arch/arm/plat-samsung/s3c-pl330.c | 1244 ----------------- 5 files changed, 6 insertions(+), 1288 deletions(-) delete mode 100644 arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h delete mode 100644 arch/arm/plat-samsung/s3c-pl330.c diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index e6f01ab86208..0a3eec616d61 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -300,12 +300,6 @@ config S3C_DMA help Internal configuration for S3C DMA core -config S3C_PL330_DMA - bool - select PL330 - help - S3C DMA API Driver for PL330 DMAC. - config SAMSUNG_DMADEV bool select DMADEVICES diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index e2ee0b8a3763..90758494cad8 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -67,8 +67,6 @@ obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o -obj-$(CONFIG_S3C_PL330_DMA) += s3c-pl330.o s3c-dma-ops.o - # PM support obj-$(CONFIG_PM) += pm.o diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h index 2916920034f0..9a1dadb0218e 100644 --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -11,9 +11,6 @@ #ifndef __DMA_PL330_H_ #define __DMA_PL330_H_ __FILE__ -#define S3C2410_DMAF_AUTOSTART (1 << 0) -#define S3C2410_DMAF_CIRCULAR (1 << 1) - /* * PL330 can assign any channel to communicate with * any of the peripherals attched to the DMAC. @@ -88,6 +85,10 @@ enum dma_ch { DMACH_MAX, }; +struct s3c2410_dma_client { + char *name; +}; + static inline bool s3c_dma_has_circular(void) { return true; @@ -97,6 +98,7 @@ static inline bool samsung_dma_is_dmadev(void) { return true; } -#include + +#include #endif /* __DMA_PL330_H_ */ diff --git a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h b/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h deleted file mode 100644 index 64fdf66ff9cf..000000000000 --- a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h +++ /dev/null @@ -1,32 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h - * - * Copyright (C) 2010 Samsung Electronics Co. Ltd. - * Jaswinder Singh - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __S3C_PL330_PDATA_H -#define __S3C_PL330_PDATA_H - -#include - -/* - * Every PL330 DMAC has max 32 peripheral interfaces, - * of which some may be not be really used in your - * DMAC's configuration. - * Populate this array of 32 peri i/fs with relevant - * channel IDs for used peri i/f and DMACH_MAX for - * those unused. - * - * The platforms just need to provide this info - * to the S3C DMA API driver for PL330. - */ -struct s3c_pl330_platdata { - enum dma_ch peri[32]; -}; - -#endif /* __S3C_PL330_PDATA_H */ diff --git a/arch/arm/plat-samsung/s3c-pl330.c b/arch/arm/plat-samsung/s3c-pl330.c deleted file mode 100644 index f85638c6f5ae..000000000000 --- a/arch/arm/plat-samsung/s3c-pl330.c +++ /dev/null @@ -1,1244 +0,0 @@ -/* linux/arch/arm/plat-samsung/s3c-pl330.c - * - * Copyright (C) 2010 Samsung Electronics Co. Ltd. - * Jaswinder Singh - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -/** - * struct s3c_pl330_dmac - Logical representation of a PL330 DMAC. - * @busy_chan: Number of channels currently busy. - * @peri: List of IDs of peripherals this DMAC can work with. - * @node: To attach to the global list of DMACs. - * @pi: PL330 configuration info for the DMAC. - * @kmcache: Pool to quickly allocate xfers for all channels in the dmac. - * @clk: Pointer of DMAC operation clock. - */ -struct s3c_pl330_dmac { - unsigned busy_chan; - enum dma_ch *peri; - struct list_head node; - struct pl330_info *pi; - struct kmem_cache *kmcache; - struct clk *clk; -}; - -/** - * struct s3c_pl330_xfer - A request submitted by S3C DMA clients. - * @token: Xfer ID provided by the client. - * @node: To attach to the list of xfers on a channel. - * @px: Xfer for PL330 core. - * @chan: Owner channel of this xfer. - */ -struct s3c_pl330_xfer { - void *token; - struct list_head node; - struct pl330_xfer px; - struct s3c_pl330_chan *chan; -}; - -/** - * struct s3c_pl330_chan - Logical channel to communicate with - * a Physical peripheral. - * @pl330_chan_id: Token of a hardware channel thread of PL330 DMAC. - * NULL if the channel is available to be acquired. - * @id: ID of the peripheral that this channel can communicate with. - * @options: Options specified by the client. - * @sdaddr: Address provided via s3c2410_dma_devconfig. - * @node: To attach to the global list of channels. - * @lrq: Pointer to the last submitted pl330_req to PL330 core. - * @xfer_list: To manage list of xfers enqueued. - * @req: Two requests to communicate with the PL330 engine. - * @callback_fn: Callback function to the client. - * @rqcfg: Channel configuration for the xfers. - * @xfer_head: Pointer to the xfer to be next executed. - * @dmac: Pointer to the DMAC that manages this channel, NULL if the - * channel is available to be acquired. - * @client: Client of this channel. NULL if the - * channel is available to be acquired. - */ -struct s3c_pl330_chan { - void *pl330_chan_id; - enum dma_ch id; - unsigned int options; - unsigned long sdaddr; - struct list_head node; - struct pl330_req *lrq; - struct list_head xfer_list; - struct pl330_req req[2]; - s3c2410_dma_cbfn_t callback_fn; - struct pl330_reqcfg rqcfg; - struct s3c_pl330_xfer *xfer_head; - struct s3c_pl330_dmac *dmac; - struct s3c2410_dma_client *client; -}; - -/* All DMACs in the platform */ -static LIST_HEAD(dmac_list); - -/* All channels to peripherals in the platform */ -static LIST_HEAD(chan_list); - -/* - * Since we add resources(DMACs and Channels) to the global pool, - * we need to guard access to the resources using a global lock - */ -static DEFINE_SPINLOCK(res_lock); - -/* Returns the channel with ID 'id' in the chan_list */ -static struct s3c_pl330_chan *id_to_chan(const enum dma_ch id) -{ - struct s3c_pl330_chan *ch; - - list_for_each_entry(ch, &chan_list, node) - if (ch->id == id) - return ch; - - return NULL; -} - -/* Allocate a new channel with ID 'id' and add to chan_list */ -static void chan_add(const enum dma_ch id) -{ - struct s3c_pl330_chan *ch = id_to_chan(id); - - /* Return if the channel already exists */ - if (ch) - return; - - ch = kmalloc(sizeof(*ch), GFP_KERNEL); - /* Return silently to work with other channels */ - if (!ch) - return; - - ch->id = id; - ch->dmac = NULL; - - list_add_tail(&ch->node, &chan_list); -} - -/* If the channel is not yet acquired by any client */ -static bool chan_free(struct s3c_pl330_chan *ch) -{ - if (!ch) - return false; - - /* Channel points to some DMAC only when it's acquired */ - return ch->dmac ? false : true; -} - -/* - * Returns 0 is peripheral i/f is invalid or not present on the dmac. - * Index + 1, otherwise. - */ -static unsigned iface_of_dmac(struct s3c_pl330_dmac *dmac, enum dma_ch ch_id) -{ - enum dma_ch *id = dmac->peri; - int i; - - /* Discount invalid markers */ - if (ch_id == DMACH_MAX) - return 0; - - for (i = 0; i < PL330_MAX_PERI; i++) - if (id[i] == ch_id) - return i + 1; - - return 0; -} - -/* If all channel threads of the DMAC are busy */ -static inline bool dmac_busy(struct s3c_pl330_dmac *dmac) -{ - struct pl330_info *pi = dmac->pi; - - return (dmac->busy_chan < pi->pcfg.num_chan) ? false : true; -} - -/* - * Returns the number of free channels that - * can be handled by this dmac only. - */ -static unsigned ch_onlyby_dmac(struct s3c_pl330_dmac *dmac) -{ - enum dma_ch *id = dmac->peri; - struct s3c_pl330_dmac *d; - struct s3c_pl330_chan *ch; - unsigned found, count = 0; - enum dma_ch p; - int i; - - for (i = 0; i < PL330_MAX_PERI; i++) { - p = id[i]; - ch = id_to_chan(p); - - if (p == DMACH_MAX || !chan_free(ch)) - continue; - - found = 0; - list_for_each_entry(d, &dmac_list, node) { - if (d != dmac && iface_of_dmac(d, ch->id)) { - found = 1; - break; - } - } - if (!found) - count++; - } - - return count; -} - -/* - * Measure of suitability of 'dmac' handling 'ch' - * - * 0 indicates 'dmac' can not handle 'ch' either - * because it is not supported by the hardware or - * because all dmac channels are currently busy. - * - * >0 vlaue indicates 'dmac' has the capability. - * The bigger the value the more suitable the dmac. - */ -#define MAX_SUIT UINT_MAX -#define MIN_SUIT 0 - -static unsigned suitablility(struct s3c_pl330_dmac *dmac, - struct s3c_pl330_chan *ch) -{ - struct pl330_info *pi = dmac->pi; - enum dma_ch *id = dmac->peri; - struct s3c_pl330_dmac *d; - unsigned s; - int i; - - s = MIN_SUIT; - /* If all the DMAC channel threads are busy */ - if (dmac_busy(dmac)) - return s; - - for (i = 0; i < PL330_MAX_PERI; i++) - if (id[i] == ch->id) - break; - - /* If the 'dmac' can't talk to 'ch' */ - if (i == PL330_MAX_PERI) - return s; - - s = MAX_SUIT; - list_for_each_entry(d, &dmac_list, node) { - /* - * If some other dmac can talk to this - * peri and has some channel free. - */ - if (d != dmac && iface_of_dmac(d, ch->id) && !dmac_busy(d)) { - s = 0; - break; - } - } - if (s) - return s; - - s = 100; - - /* Good if free chans are more, bad otherwise */ - s += (pi->pcfg.num_chan - dmac->busy_chan) - ch_onlyby_dmac(dmac); - - return s; -} - -/* More than one DMAC may have capability to transfer data with the - * peripheral. This function assigns most suitable DMAC to manage the - * channel and hence communicate with the peripheral. - */ -static struct s3c_pl330_dmac *map_chan_to_dmac(struct s3c_pl330_chan *ch) -{ - struct s3c_pl330_dmac *d, *dmac = NULL; - unsigned sn, sl = MIN_SUIT; - - list_for_each_entry(d, &dmac_list, node) { - sn = suitablility(d, ch); - - if (sn == MAX_SUIT) - return d; - - if (sn > sl) - dmac = d; - } - - return dmac; -} - -/* Acquire the channel for peripheral 'id' */ -static struct s3c_pl330_chan *chan_acquire(const enum dma_ch id) -{ - struct s3c_pl330_chan *ch = id_to_chan(id); - struct s3c_pl330_dmac *dmac; - - /* If the channel doesn't exist or is already acquired */ - if (!ch || !chan_free(ch)) { - ch = NULL; - goto acq_exit; - } - - dmac = map_chan_to_dmac(ch); - /* If couldn't map */ - if (!dmac) { - ch = NULL; - goto acq_exit; - } - - dmac->busy_chan++; - ch->dmac = dmac; - -acq_exit: - return ch; -} - -/* Delete xfer from the queue */ -static inline void del_from_queue(struct s3c_pl330_xfer *xfer) -{ - struct s3c_pl330_xfer *t; - struct s3c_pl330_chan *ch; - int found; - - if (!xfer) - return; - - ch = xfer->chan; - - /* Make sure xfer is in the queue */ - found = 0; - list_for_each_entry(t, &ch->xfer_list, node) - if (t == xfer) { - found = 1; - break; - } - - if (!found) - return; - - /* If xfer is last entry in the queue */ - if (xfer->node.next == &ch->xfer_list) - t = list_entry(ch->xfer_list.next, - struct s3c_pl330_xfer, node); - else - t = list_entry(xfer->node.next, - struct s3c_pl330_xfer, node); - - /* If there was only one node left */ - if (t == xfer) - ch->xfer_head = NULL; - else if (ch->xfer_head == xfer) - ch->xfer_head = t; - - list_del(&xfer->node); -} - -/* Provides pointer to the next xfer in the queue. - * If CIRCULAR option is set, the list is left intact, - * otherwise the xfer is removed from the list. - * Forced delete 'pluck' can be set to override the CIRCULAR option. - */ -static struct s3c_pl330_xfer *get_from_queue(struct s3c_pl330_chan *ch, - int pluck) -{ - struct s3c_pl330_xfer *xfer = ch->xfer_head; - - if (!xfer) - return NULL; - - /* If xfer is last entry in the queue */ - if (xfer->node.next == &ch->xfer_list) - ch->xfer_head = list_entry(ch->xfer_list.next, - struct s3c_pl330_xfer, node); - else - ch->xfer_head = list_entry(xfer->node.next, - struct s3c_pl330_xfer, node); - - if (pluck || !(ch->options & S3C2410_DMAF_CIRCULAR)) - del_from_queue(xfer); - - return xfer; -} - -static inline void add_to_queue(struct s3c_pl330_chan *ch, - struct s3c_pl330_xfer *xfer, int front) -{ - struct pl330_xfer *xt; - - /* If queue empty */ - if (ch->xfer_head == NULL) - ch->xfer_head = xfer; - - xt = &ch->xfer_head->px; - /* If the head already submitted (CIRCULAR head) */ - if (ch->options & S3C2410_DMAF_CIRCULAR && - (xt == ch->req[0].x || xt == ch->req[1].x)) - ch->xfer_head = xfer; - - /* If this is a resubmission, it should go at the head */ - if (front) { - ch->xfer_head = xfer; - list_add(&xfer->node, &ch->xfer_list); - } else { - list_add_tail(&xfer->node, &ch->xfer_list); - } -} - -static inline void _finish_off(struct s3c_pl330_xfer *xfer, - enum s3c2410_dma_buffresult res, int ffree) -{ - struct s3c_pl330_chan *ch; - - if (!xfer) - return; - - ch = xfer->chan; - - /* Do callback */ - if (ch->callback_fn) - ch->callback_fn(NULL, xfer->token, xfer->px.bytes, res); - - /* Force Free or if buffer is not needed anymore */ - if (ffree || !(ch->options & S3C2410_DMAF_CIRCULAR)) - kmem_cache_free(ch->dmac->kmcache, xfer); -} - -static inline int s3c_pl330_submit(struct s3c_pl330_chan *ch, - struct pl330_req *r) -{ - struct s3c_pl330_xfer *xfer; - int ret = 0; - - /* If already submitted */ - if (r->x) - return 0; - - xfer = get_from_queue(ch, 0); - if (xfer) { - r->x = &xfer->px; - - /* Use max bandwidth for M<->M xfers */ - if (r->rqtype == MEMTOMEM) { - struct pl330_info *pi = xfer->chan->dmac->pi; - int burst = 1 << ch->rqcfg.brst_size; - u32 bytes = r->x->bytes; - int bl; - - bl = pi->pcfg.data_bus_width / 8; - bl *= pi->pcfg.data_buf_dep; - bl /= burst; - - /* src/dst_burst_len can't be more than 16 */ - if (bl > 16) - bl = 16; - - while (bl > 1) { - if (!(bytes % (bl * burst))) - break; - bl--; - } - - ch->rqcfg.brst_len = bl; - } else { - ch->rqcfg.brst_len = 1; - } - - ret = pl330_submit_req(ch->pl330_chan_id, r); - - /* If submission was successful */ - if (!ret) { - ch->lrq = r; /* latest submitted req */ - return 0; - } - - r->x = NULL; - - /* If both of the PL330 ping-pong buffers filled */ - if (ret == -EAGAIN) { - dev_err(ch->dmac->pi->dev, "%s:%d!\n", - __func__, __LINE__); - /* Queue back again */ - add_to_queue(ch, xfer, 1); - ret = 0; - } else { - dev_err(ch->dmac->pi->dev, "%s:%d!\n", - __func__, __LINE__); - _finish_off(xfer, S3C2410_RES_ERR, 0); - } - } - - return ret; -} - -static void s3c_pl330_rq(struct s3c_pl330_chan *ch, - struct pl330_req *r, enum pl330_op_err err) -{ - unsigned long flags; - struct s3c_pl330_xfer *xfer; - struct pl330_xfer *xl = r->x; - enum s3c2410_dma_buffresult res; - - spin_lock_irqsave(&res_lock, flags); - - r->x = NULL; - - s3c_pl330_submit(ch, r); - - spin_unlock_irqrestore(&res_lock, flags); - - /* Map result to S3C DMA API */ - if (err == PL330_ERR_NONE) - res = S3C2410_RES_OK; - else if (err == PL330_ERR_ABORT) - res = S3C2410_RES_ABORT; - else - res = S3C2410_RES_ERR; - - /* If last request had some xfer */ - if (xl) { - xfer = container_of(xl, struct s3c_pl330_xfer, px); - _finish_off(xfer, res, 0); - } else { - dev_info(ch->dmac->pi->dev, "%s:%d No Xfer?!\n", - __func__, __LINE__); - } -} - -static void s3c_pl330_rq0(void *token, enum pl330_op_err err) -{ - struct pl330_req *r = token; - struct s3c_pl330_chan *ch = container_of(r, - struct s3c_pl330_chan, req[0]); - s3c_pl330_rq(ch, r, err); -} - -static void s3c_pl330_rq1(void *token, enum pl330_op_err err) -{ - struct pl330_req *r = token; - struct s3c_pl330_chan *ch = container_of(r, - struct s3c_pl330_chan, req[1]); - s3c_pl330_rq(ch, r, err); -} - -/* Release an acquired channel */ -static void chan_release(struct s3c_pl330_chan *ch) -{ - struct s3c_pl330_dmac *dmac; - - if (chan_free(ch)) - return; - - dmac = ch->dmac; - ch->dmac = NULL; - dmac->busy_chan--; -} - -int s3c2410_dma_ctrl(enum dma_ch id, enum s3c2410_chan_op op) -{ - struct s3c_pl330_xfer *xfer; - enum pl330_chan_op pl330op; - struct s3c_pl330_chan *ch; - unsigned long flags; - int idx, ret; - - spin_lock_irqsave(&res_lock, flags); - - ch = id_to_chan(id); - - if (!ch || chan_free(ch)) { - ret = -EINVAL; - goto ctrl_exit; - } - - switch (op) { - case S3C2410_DMAOP_START: - /* Make sure both reqs are enqueued */ - idx = (ch->lrq == &ch->req[0]) ? 1 : 0; - s3c_pl330_submit(ch, &ch->req[idx]); - s3c_pl330_submit(ch, &ch->req[1 - idx]); - pl330op = PL330_OP_START; - break; - - case S3C2410_DMAOP_STOP: - pl330op = PL330_OP_ABORT; - break; - - case S3C2410_DMAOP_FLUSH: - pl330op = PL330_OP_FLUSH; - break; - - case S3C2410_DMAOP_PAUSE: - case S3C2410_DMAOP_RESUME: - case S3C2410_DMAOP_TIMEOUT: - case S3C2410_DMAOP_STARTED: - spin_unlock_irqrestore(&res_lock, flags); - return 0; - - default: - spin_unlock_irqrestore(&res_lock, flags); - return -EINVAL; - } - - ret = pl330_chan_ctrl(ch->pl330_chan_id, pl330op); - - if (pl330op == PL330_OP_START) { - spin_unlock_irqrestore(&res_lock, flags); - return ret; - } - - idx = (ch->lrq == &ch->req[0]) ? 1 : 0; - - /* Abort the current xfer */ - if (ch->req[idx].x) { - xfer = container_of(ch->req[idx].x, - struct s3c_pl330_xfer, px); - - /* Drop xfer during FLUSH */ - if (pl330op == PL330_OP_FLUSH) - del_from_queue(xfer); - - ch->req[idx].x = NULL; - - spin_unlock_irqrestore(&res_lock, flags); - _finish_off(xfer, S3C2410_RES_ABORT, - pl330op == PL330_OP_FLUSH ? 1 : 0); - spin_lock_irqsave(&res_lock, flags); - } - - /* Flush the whole queue */ - if (pl330op == PL330_OP_FLUSH) { - - if (ch->req[1 - idx].x) { - xfer = container_of(ch->req[1 - idx].x, - struct s3c_pl330_xfer, px); - - del_from_queue(xfer); - - ch->req[1 - idx].x = NULL; - - spin_unlock_irqrestore(&res_lock, flags); - _finish_off(xfer, S3C2410_RES_ABORT, 1); - spin_lock_irqsave(&res_lock, flags); - } - - /* Finish off the remaining in the queue */ - xfer = ch->xfer_head; - while (xfer) { - - del_from_queue(xfer); - - spin_unlock_irqrestore(&res_lock, flags); - _finish_off(xfer, S3C2410_RES_ABORT, 1); - spin_lock_irqsave(&res_lock, flags); - - xfer = ch->xfer_head; - } - } - -ctrl_exit: - spin_unlock_irqrestore(&res_lock, flags); - - return ret; -} -EXPORT_SYMBOL(s3c2410_dma_ctrl); - -int s3c2410_dma_enqueue(enum dma_ch id, void *token, - dma_addr_t addr, int size) -{ - struct s3c_pl330_chan *ch; - struct s3c_pl330_xfer *xfer; - unsigned long flags; - int idx, ret = 0; - - spin_lock_irqsave(&res_lock, flags); - - ch = id_to_chan(id); - - /* Error if invalid or free channel */ - if (!ch || chan_free(ch)) { - ret = -EINVAL; - goto enq_exit; - } - - /* Error if size is unaligned */ - if (ch->rqcfg.brst_size && size % (1 << ch->rqcfg.brst_size)) { - ret = -EINVAL; - goto enq_exit; - } - - xfer = kmem_cache_alloc(ch->dmac->kmcache, GFP_ATOMIC); - if (!xfer) { - ret = -ENOMEM; - goto enq_exit; - } - - xfer->token = token; - xfer->chan = ch; - xfer->px.bytes = size; - xfer->px.next = NULL; /* Single request */ - - /* For S3C DMA API, direction is always fixed for all xfers */ - if (ch->req[0].rqtype == MEMTODEV) { - xfer->px.src_addr = addr; - xfer->px.dst_addr = ch->sdaddr; - } else { - xfer->px.src_addr = ch->sdaddr; - xfer->px.dst_addr = addr; - } - - add_to_queue(ch, xfer, 0); - - /* Try submitting on either request */ - idx = (ch->lrq == &ch->req[0]) ? 1 : 0; - - if (!ch->req[idx].x) - s3c_pl330_submit(ch, &ch->req[idx]); - else - s3c_pl330_submit(ch, &ch->req[1 - idx]); - - spin_unlock_irqrestore(&res_lock, flags); - - if (ch->options & S3C2410_DMAF_AUTOSTART) - s3c2410_dma_ctrl(id, S3C2410_DMAOP_START); - - return 0; - -enq_exit: - spin_unlock_irqrestore(&res_lock, flags); - - return ret; -} -EXPORT_SYMBOL(s3c2410_dma_enqueue); - -int s3c2410_dma_request(enum dma_ch id, - struct s3c2410_dma_client *client, - void *dev) -{ - struct s3c_pl330_dmac *dmac; - struct s3c_pl330_chan *ch; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&res_lock, flags); - - ch = chan_acquire(id); - if (!ch) { - ret = -EBUSY; - goto req_exit; - } - - dmac = ch->dmac; - - ch->pl330_chan_id = pl330_request_channel(dmac->pi); - if (!ch->pl330_chan_id) { - chan_release(ch); - ret = -EBUSY; - goto req_exit; - } - - ch->client = client; - ch->options = 0; /* Clear any option */ - ch->callback_fn = NULL; /* Clear any callback */ - ch->lrq = NULL; - - ch->rqcfg.brst_size = 2; /* Default word size */ - ch->rqcfg.swap = SWAP_NO; - ch->rqcfg.scctl = SCCTRL0; /* Noncacheable and nonbufferable */ - ch->rqcfg.dcctl = DCCTRL0; /* Noncacheable and nonbufferable */ - ch->rqcfg.privileged = 0; - ch->rqcfg.insnaccess = 0; - - /* Set invalid direction */ - ch->req[0].rqtype = DEVTODEV; - ch->req[1].rqtype = ch->req[0].rqtype; - - ch->req[0].cfg = &ch->rqcfg; - ch->req[1].cfg = ch->req[0].cfg; - - ch->req[0].peri = iface_of_dmac(dmac, id) - 1; /* Original index */ - ch->req[1].peri = ch->req[0].peri; - - ch->req[0].token = &ch->req[0]; - ch->req[0].xfer_cb = s3c_pl330_rq0; - ch->req[1].token = &ch->req[1]; - ch->req[1].xfer_cb = s3c_pl330_rq1; - - ch->req[0].x = NULL; - ch->req[1].x = NULL; - - /* Reset xfer list */ - INIT_LIST_HEAD(&ch->xfer_list); - ch->xfer_head = NULL; - -req_exit: - spin_unlock_irqrestore(&res_lock, flags); - - return ret; -} -EXPORT_SYMBOL(s3c2410_dma_request); - -int s3c2410_dma_free(enum dma_ch id, struct s3c2410_dma_client *client) -{ - struct s3c_pl330_chan *ch; - struct s3c_pl330_xfer *xfer; - unsigned long flags; - int ret = 0; - unsigned idx; - - spin_lock_irqsave(&res_lock, flags); - - ch = id_to_chan(id); - - if (!ch || chan_free(ch)) - goto free_exit; - - /* Refuse if someone else wanted to free the channel */ - if (ch->client != client) { - ret = -EBUSY; - goto free_exit; - } - - /* Stop any active xfer, Flushe the queue and do callbacks */ - pl330_chan_ctrl(ch->pl330_chan_id, PL330_OP_FLUSH); - - /* Abort the submitted requests */ - idx = (ch->lrq == &ch->req[0]) ? 1 : 0; - - if (ch->req[idx].x) { - xfer = container_of(ch->req[idx].x, - struct s3c_pl330_xfer, px); - - ch->req[idx].x = NULL; - del_from_queue(xfer); - - spin_unlock_irqrestore(&res_lock, flags); - _finish_off(xfer, S3C2410_RES_ABORT, 1); - spin_lock_irqsave(&res_lock, flags); - } - - if (ch->req[1 - idx].x) { - xfer = container_of(ch->req[1 - idx].x, - struct s3c_pl330_xfer, px); - - ch->req[1 - idx].x = NULL; - del_from_queue(xfer); - - spin_unlock_irqrestore(&res_lock, flags); - _finish_off(xfer, S3C2410_RES_ABORT, 1); - spin_lock_irqsave(&res_lock, flags); - } - - /* Pluck and Abort the queued requests in order */ - do { - xfer = get_from_queue(ch, 1); - - spin_unlock_irqrestore(&res_lock, flags); - _finish_off(xfer, S3C2410_RES_ABORT, 1); - spin_lock_irqsave(&res_lock, flags); - } while (xfer); - - ch->client = NULL; - - pl330_release_channel(ch->pl330_chan_id); - - ch->pl330_chan_id = NULL; - - chan_release(ch); - -free_exit: - spin_unlock_irqrestore(&res_lock, flags); - - return ret; -} -EXPORT_SYMBOL(s3c2410_dma_free); - -int s3c2410_dma_config(enum dma_ch id, int xferunit) -{ - struct s3c_pl330_chan *ch; - struct pl330_info *pi; - unsigned long flags; - int i, dbwidth, ret = 0; - - spin_lock_irqsave(&res_lock, flags); - - ch = id_to_chan(id); - - if (!ch || chan_free(ch)) { - ret = -EINVAL; - goto cfg_exit; - } - - pi = ch->dmac->pi; - dbwidth = pi->pcfg.data_bus_width / 8; - - /* Max size of xfer can be pcfg.data_bus_width */ - if (xferunit > dbwidth) { - ret = -EINVAL; - goto cfg_exit; - } - - i = 0; - while (xferunit != (1 << i)) - i++; - - /* If valid value */ - if (xferunit == (1 << i)) - ch->rqcfg.brst_size = i; - else - ret = -EINVAL; - -cfg_exit: - spin_unlock_irqrestore(&res_lock, flags); - - return ret; -} -EXPORT_SYMBOL(s3c2410_dma_config); - -/* Options that are supported by this driver */ -#define S3C_PL330_FLAGS (S3C2410_DMAF_CIRCULAR | S3C2410_DMAF_AUTOSTART) - -int s3c2410_dma_setflags(enum dma_ch id, unsigned int options) -{ - struct s3c_pl330_chan *ch; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&res_lock, flags); - - ch = id_to_chan(id); - - if (!ch || chan_free(ch) || options & ~(S3C_PL330_FLAGS)) - ret = -EINVAL; - else - ch->options = options; - - spin_unlock_irqrestore(&res_lock, flags); - - return 0; -} -EXPORT_SYMBOL(s3c2410_dma_setflags); - -int s3c2410_dma_set_buffdone_fn(enum dma_ch id, s3c2410_dma_cbfn_t rtn) -{ - struct s3c_pl330_chan *ch; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&res_lock, flags); - - ch = id_to_chan(id); - - if (!ch || chan_free(ch)) - ret = -EINVAL; - else - ch->callback_fn = rtn; - - spin_unlock_irqrestore(&res_lock, flags); - - return ret; -} -EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); - -int s3c2410_dma_devconfig(enum dma_ch id, enum s3c2410_dmasrc source, - unsigned long address) -{ - struct s3c_pl330_chan *ch; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&res_lock, flags); - - ch = id_to_chan(id); - - if (!ch || chan_free(ch)) { - ret = -EINVAL; - goto devcfg_exit; - } - - switch (source) { - case S3C2410_DMASRC_HW: /* P->M */ - ch->req[0].rqtype = DEVTOMEM; - ch->req[1].rqtype = DEVTOMEM; - ch->rqcfg.src_inc = 0; - ch->rqcfg.dst_inc = 1; - break; - case S3C2410_DMASRC_MEM: /* M->P */ - ch->req[0].rqtype = MEMTODEV; - ch->req[1].rqtype = MEMTODEV; - ch->rqcfg.src_inc = 1; - ch->rqcfg.dst_inc = 0; - break; - default: - ret = -EINVAL; - goto devcfg_exit; - } - - ch->sdaddr = address; - -devcfg_exit: - spin_unlock_irqrestore(&res_lock, flags); - - return ret; -} -EXPORT_SYMBOL(s3c2410_dma_devconfig); - -int s3c2410_dma_getposition(enum dma_ch id, dma_addr_t *src, dma_addr_t *dst) -{ - struct s3c_pl330_chan *ch = id_to_chan(id); - struct pl330_chanstatus status; - int ret; - - if (!ch || chan_free(ch)) - return -EINVAL; - - ret = pl330_chan_status(ch->pl330_chan_id, &status); - if (ret < 0) - return ret; - - *src = status.src_addr; - *dst = status.dst_addr; - - return 0; -} -EXPORT_SYMBOL(s3c2410_dma_getposition); - -static irqreturn_t pl330_irq_handler(int irq, void *data) -{ - if (pl330_update(data)) - return IRQ_HANDLED; - else - return IRQ_NONE; -} - -static int pl330_probe(struct platform_device *pdev) -{ - struct s3c_pl330_dmac *s3c_pl330_dmac; - struct s3c_pl330_platdata *pl330pd; - struct pl330_info *pl330_info; - struct resource *res; - int i, ret, irq; - - pl330pd = pdev->dev.platform_data; - - /* Can't do without the list of _32_ peripherals */ - if (!pl330pd || !pl330pd->peri) { - dev_err(&pdev->dev, "platform data missing!\n"); - return -ENODEV; - } - - pl330_info = kzalloc(sizeof(*pl330_info), GFP_KERNEL); - if (!pl330_info) - return -ENOMEM; - - pl330_info->pl330_data = NULL; - pl330_info->dev = &pdev->dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto probe_err1; - } - - request_mem_region(res->start, resource_size(res), pdev->name); - - pl330_info->base = ioremap(res->start, resource_size(res)); - if (!pl330_info->base) { - ret = -ENXIO; - goto probe_err2; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto probe_err3; - } - - ret = request_irq(irq, pl330_irq_handler, 0, - dev_name(&pdev->dev), pl330_info); - if (ret) - goto probe_err4; - - /* Allocate a new DMAC */ - s3c_pl330_dmac = kmalloc(sizeof(*s3c_pl330_dmac), GFP_KERNEL); - if (!s3c_pl330_dmac) { - ret = -ENOMEM; - goto probe_err5; - } - - /* Get operation clock and enable it */ - s3c_pl330_dmac->clk = clk_get(&pdev->dev, "pdma"); - if (IS_ERR(s3c_pl330_dmac->clk)) { - dev_err(&pdev->dev, "Cannot get operation clock.\n"); - ret = -EINVAL; - goto probe_err6; - } - clk_enable(s3c_pl330_dmac->clk); - - ret = pl330_add(pl330_info); - if (ret) - goto probe_err7; - - /* Hook the info */ - s3c_pl330_dmac->pi = pl330_info; - - /* No busy channels */ - s3c_pl330_dmac->busy_chan = 0; - - s3c_pl330_dmac->kmcache = kmem_cache_create(dev_name(&pdev->dev), - sizeof(struct s3c_pl330_xfer), 0, 0, NULL); - - if (!s3c_pl330_dmac->kmcache) { - ret = -ENOMEM; - goto probe_err8; - } - - /* Get the list of peripherals */ - s3c_pl330_dmac->peri = pl330pd->peri; - - /* Attach to the list of DMACs */ - list_add_tail(&s3c_pl330_dmac->node, &dmac_list); - - /* Create a channel for each peripheral in the DMAC - * that is, if it doesn't already exist - */ - for (i = 0; i < PL330_MAX_PERI; i++) - if (s3c_pl330_dmac->peri[i] != DMACH_MAX) - chan_add(s3c_pl330_dmac->peri[i]); - - printk(KERN_INFO - "Loaded driver for PL330 DMAC-%d %s\n", pdev->id, pdev->name); - printk(KERN_INFO - "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n", - pl330_info->pcfg.data_buf_dep, - pl330_info->pcfg.data_bus_width / 8, pl330_info->pcfg.num_chan, - pl330_info->pcfg.num_peri, pl330_info->pcfg.num_events); - - return 0; - -probe_err8: - pl330_del(pl330_info); -probe_err7: - clk_disable(s3c_pl330_dmac->clk); - clk_put(s3c_pl330_dmac->clk); -probe_err6: - kfree(s3c_pl330_dmac); -probe_err5: - free_irq(irq, pl330_info); -probe_err4: -probe_err3: - iounmap(pl330_info->base); -probe_err2: - release_mem_region(res->start, resource_size(res)); -probe_err1: - kfree(pl330_info); - - return ret; -} - -static int pl330_remove(struct platform_device *pdev) -{ - struct s3c_pl330_dmac *dmac, *d; - struct s3c_pl330_chan *ch; - unsigned long flags; - int del, found; - - if (!pdev->dev.platform_data) - return -EINVAL; - - spin_lock_irqsave(&res_lock, flags); - - found = 0; - list_for_each_entry(d, &dmac_list, node) - if (d->pi->dev == &pdev->dev) { - found = 1; - break; - } - - if (!found) { - spin_unlock_irqrestore(&res_lock, flags); - return 0; - } - - dmac = d; - - /* Remove all Channels that are managed only by this DMAC */ - list_for_each_entry(ch, &chan_list, node) { - - /* Only channels that are handled by this DMAC */ - if (iface_of_dmac(dmac, ch->id)) - del = 1; - else - continue; - - /* Don't remove if some other DMAC has it too */ - list_for_each_entry(d, &dmac_list, node) - if (d != dmac && iface_of_dmac(d, ch->id)) { - del = 0; - break; - } - - if (del) { - spin_unlock_irqrestore(&res_lock, flags); - s3c2410_dma_free(ch->id, ch->client); - spin_lock_irqsave(&res_lock, flags); - list_del(&ch->node); - kfree(ch); - } - } - - /* Disable operation clock */ - clk_disable(dmac->clk); - clk_put(dmac->clk); - - /* Remove the DMAC */ - list_del(&dmac->node); - kfree(dmac); - - spin_unlock_irqrestore(&res_lock, flags); - - return 0; -} - -static struct platform_driver pl330_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "s3c-pl330", - }, - .probe = pl330_probe, - .remove = pl330_remove, -}; - -static int __init pl330_init(void) -{ - return platform_driver_register(&pl330_driver); -} -module_init(pl330_init); - -static void __exit pl330_exit(void) -{ - platform_driver_unregister(&pl330_driver); - return; -} -module_exit(pl330_exit); - -MODULE_AUTHOR("Jaswinder Singh "); -MODULE_DESCRIPTION("Driver for PL330 DMA Controller"); -MODULE_LICENSE("GPL"); From 39d3e8074e44c1953928a0b91bc328f552c5fc79 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:41 +0900 Subject: [PATCH 0362/1596] spi/s3c64xx: Add support DMA engine API This patch adds to support DMA generic API to transfer raw SPI data. Basiclly the spi driver uses DMA generic API if architecture supports it. Otherwise, uses Samsung specific S3C-PL330 APIs. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Acked-by: Grant Likely Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- drivers/spi/spi-s3c64xx.c | 141 +++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 72 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 595dacc7645f..24f49032ec35 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -171,6 +171,9 @@ struct s3c64xx_spi_driver_data { unsigned state; unsigned cur_mode, cur_bpw; unsigned cur_speed; + unsigned rx_ch; + unsigned tx_ch; + struct samsung_dma_ops *ops; }; static struct s3c2410_dma_client s3c64xx_spi_dma_client = { @@ -226,6 +229,38 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) writel(val, regs + S3C64XX_SPI_CH_CFG); } +static void s3c64xx_spi_dma_rxcb(void *data) +{ + struct s3c64xx_spi_driver_data *sdd + = (struct s3c64xx_spi_driver_data *)data; + unsigned long flags; + + spin_lock_irqsave(&sdd->lock, flags); + + sdd->state &= ~RXBUSY; + /* If the other done */ + if (!(sdd->state & TXBUSY)) + complete(&sdd->xfer_completion); + + spin_unlock_irqrestore(&sdd->lock, flags); +} + +static void s3c64xx_spi_dma_txcb(void *data) +{ + struct s3c64xx_spi_driver_data *sdd + = (struct s3c64xx_spi_driver_data *)data; + unsigned long flags; + + spin_lock_irqsave(&sdd->lock, flags); + + sdd->state &= ~TXBUSY; + /* If the other done */ + if (!(sdd->state & RXBUSY)) + complete(&sdd->xfer_completion); + + spin_unlock_irqrestore(&sdd->lock, flags); +} + static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi, struct spi_transfer *xfer, int dma_mode) @@ -233,6 +268,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 modecfg, chcfg; + struct samsung_dma_prep_info info; modecfg = readl(regs + S3C64XX_SPI_MODE_CFG); modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON); @@ -258,10 +294,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; - s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8); - s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd, - xfer->tx_dma, xfer->len); - s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START); + info.cap = DMA_SLAVE; + info.direction = DMA_TO_DEVICE; + info.buf = xfer->tx_dma; + info.len = xfer->len; + info.fp = s3c64xx_spi_dma_txcb; + info.fp_param = sdd; + sdd->ops->prepare(sdd->tx_ch, &info); + sdd->ops->trigger(sdd->tx_ch); } else { switch (sdd->cur_bpw) { case 32: @@ -293,10 +333,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); - s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8); - s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd, - xfer->rx_dma, xfer->len); - s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START); + info.cap = DMA_SLAVE; + info.direction = DMA_FROM_DEVICE; + info.buf = xfer->rx_dma; + info.len = xfer->len; + info.fp = s3c64xx_spi_dma_rxcb; + info.fp_param = sdd; + sdd->ops->prepare(sdd->rx_ch, &info); + sdd->ops->trigger(sdd->rx_ch); } } @@ -482,46 +526,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) } } -static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, - int size, enum s3c2410_dma_buffresult res) -{ - struct s3c64xx_spi_driver_data *sdd = buf_id; - unsigned long flags; - - spin_lock_irqsave(&sdd->lock, flags); - - if (res == S3C2410_RES_OK) - sdd->state &= ~RXBUSY; - else - dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size); - - /* If the other done */ - if (!(sdd->state & TXBUSY)) - complete(&sdd->xfer_completion); - - spin_unlock_irqrestore(&sdd->lock, flags); -} - -static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id, - int size, enum s3c2410_dma_buffresult res) -{ - struct s3c64xx_spi_driver_data *sdd = buf_id; - unsigned long flags; - - spin_lock_irqsave(&sdd->lock, flags); - - if (res == S3C2410_RES_OK) - sdd->state &= ~TXBUSY; - else - dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size); - - /* If the other done */ - if (!(sdd->state & RXBUSY)) - complete(&sdd->xfer_completion); - - spin_unlock_irqrestore(&sdd->lock, flags); -} - #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, @@ -696,12 +700,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, if (use_dma) { if (xfer->tx_buf != NULL && (sdd->state & TXBUSY)) - s3c2410_dma_ctrl(sdd->tx_dmach, - S3C2410_DMAOP_FLUSH); + sdd->ops->stop(sdd->tx_ch); if (xfer->rx_buf != NULL && (sdd->state & RXBUSY)) - s3c2410_dma_ctrl(sdd->rx_dmach, - S3C2410_DMAOP_FLUSH); + sdd->ops->stop(sdd->rx_ch); } goto out; @@ -741,24 +743,19 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) { - if (s3c2410_dma_request(sdd->rx_dmach, - &s3c64xx_spi_dma_client, NULL) < 0) { - dev_err(&sdd->pdev->dev, "cannot get RxDMA\n"); - return 0; - } - s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb); - s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW, - sdd->sfr_start + S3C64XX_SPI_RX_DATA); - - if (s3c2410_dma_request(sdd->tx_dmach, - &s3c64xx_spi_dma_client, NULL) < 0) { - dev_err(&sdd->pdev->dev, "cannot get TxDMA\n"); - s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client); - return 0; - } - s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb); - s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM, - sdd->sfr_start + S3C64XX_SPI_TX_DATA); + + struct samsung_dma_info info; + sdd->ops = samsung_dma_get_ops(); + + info.cap = DMA_SLAVE; + info.client = &s3c64xx_spi_dma_client; + info.direction = DMA_FROM_DEVICE; + info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; + info.width = sdd->cur_bpw / 8; + sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info); + info.direction = DMA_TO_DEVICE; + info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; + sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info); return 1; } @@ -799,8 +796,8 @@ static void s3c64xx_spi_work(struct work_struct *work) spin_unlock_irqrestore(&sdd->lock, flags); /* Free DMA channels */ - s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client); - s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client); + sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client); + sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client); } static int s3c64xx_spi_transfer(struct spi_device *spi, From 82ab8cd7ec32194757ac73a66633be73ba88ea69 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:42 +0900 Subject: [PATCH 0363/1596] spi/s3c64xx: Merge dma control code This patch modifies to merge the dma control code. Original s3c64xx spi driver has each dma control code for rx and tx channel. This patch merges these dma control codes into one. With this patch, a dma setup function and callback function handle for both rx and tx channel. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Cc: Grant Likely Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- drivers/spi/spi-s3c64xx.c | 140 +++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 64 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 24f49032ec35..019a7163572f 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -131,6 +131,12 @@ #define RXBUSY (1<<2) #define TXBUSY (1<<3) +struct s3c64xx_spi_dma_data { + unsigned ch; + enum dma_data_direction direction; + enum dma_ch dmach; +}; + /** * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. * @clk: Pointer to the spi clock. @@ -164,15 +170,13 @@ struct s3c64xx_spi_driver_data { struct work_struct work; struct list_head queue; spinlock_t lock; - enum dma_ch rx_dmach; - enum dma_ch tx_dmach; unsigned long sfr_start; struct completion xfer_completion; unsigned state; unsigned cur_mode, cur_bpw; unsigned cur_speed; - unsigned rx_ch; - unsigned tx_ch; + struct s3c64xx_spi_dma_data rx_dma; + struct s3c64xx_spi_dma_data tx_dma; struct samsung_dma_ops *ops; }; @@ -229,36 +233,76 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) writel(val, regs + S3C64XX_SPI_CH_CFG); } -static void s3c64xx_spi_dma_rxcb(void *data) +static void s3c64xx_spi_dmacb(void *data) { - struct s3c64xx_spi_driver_data *sdd - = (struct s3c64xx_spi_driver_data *)data; + struct s3c64xx_spi_driver_data *sdd; + struct s3c64xx_spi_dma_data *dma = data; unsigned long flags; + if (dma->direction == DMA_FROM_DEVICE) + sdd = container_of(data, + struct s3c64xx_spi_driver_data, rx_dma); + else + sdd = container_of(data, + struct s3c64xx_spi_driver_data, tx_dma); + spin_lock_irqsave(&sdd->lock, flags); - sdd->state &= ~RXBUSY; - /* If the other done */ - if (!(sdd->state & TXBUSY)) - complete(&sdd->xfer_completion); + if (dma->direction == DMA_FROM_DEVICE) { + sdd->state &= ~RXBUSY; + if (!(sdd->state & TXBUSY)) + complete(&sdd->xfer_completion); + } else { + sdd->state &= ~TXBUSY; + if (!(sdd->state & RXBUSY)) + complete(&sdd->xfer_completion); + } spin_unlock_irqrestore(&sdd->lock, flags); } -static void s3c64xx_spi_dma_txcb(void *data) +static void prepare_dma(struct s3c64xx_spi_dma_data *dma, + unsigned len, dma_addr_t buf) { - struct s3c64xx_spi_driver_data *sdd - = (struct s3c64xx_spi_driver_data *)data; - unsigned long flags; + struct s3c64xx_spi_driver_data *sdd; + struct samsung_dma_prep_info info; - spin_lock_irqsave(&sdd->lock, flags); + if (dma->direction == DMA_FROM_DEVICE) + sdd = container_of((void *)dma, + struct s3c64xx_spi_driver_data, rx_dma); + else + sdd = container_of((void *)dma, + struct s3c64xx_spi_driver_data, tx_dma); - sdd->state &= ~TXBUSY; - /* If the other done */ - if (!(sdd->state & RXBUSY)) - complete(&sdd->xfer_completion); + info.cap = DMA_SLAVE; + info.len = len; + info.fp = s3c64xx_spi_dmacb; + info.fp_param = dma; + info.direction = dma->direction; + info.buf = buf; + + sdd->ops->prepare(dma->ch, &info); + sdd->ops->trigger(dma->ch); +} - spin_unlock_irqrestore(&sdd->lock, flags); +static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) +{ + struct samsung_dma_info info; + + sdd->ops = samsung_dma_get_ops(); + + info.cap = DMA_SLAVE; + info.client = &s3c64xx_spi_dma_client; + info.width = sdd->cur_bpw / 8; + + info.direction = sdd->rx_dma.direction; + info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; + sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info); + info.direction = sdd->tx_dma.direction; + info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; + sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info); + + return 1; } static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, @@ -268,7 +312,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; u32 modecfg, chcfg; - struct samsung_dma_prep_info info; modecfg = readl(regs + S3C64XX_SPI_MODE_CFG); modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON); @@ -294,14 +337,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; - info.cap = DMA_SLAVE; - info.direction = DMA_TO_DEVICE; - info.buf = xfer->tx_dma; - info.len = xfer->len; - info.fp = s3c64xx_spi_dma_txcb; - info.fp_param = sdd; - sdd->ops->prepare(sdd->tx_ch, &info); - sdd->ops->trigger(sdd->tx_ch); + prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma); } else { switch (sdd->cur_bpw) { case 32: @@ -333,14 +369,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); - info.cap = DMA_SLAVE; - info.direction = DMA_FROM_DEVICE; - info.buf = xfer->rx_dma; - info.len = xfer->len; - info.fp = s3c64xx_spi_dma_rxcb; - info.fp_param = sdd; - sdd->ops->prepare(sdd->rx_ch, &info); - sdd->ops->trigger(sdd->rx_ch); + prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma); } } @@ -700,10 +729,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, if (use_dma) { if (xfer->tx_buf != NULL && (sdd->state & TXBUSY)) - sdd->ops->stop(sdd->tx_ch); + sdd->ops->stop(sdd->tx_dma.ch); if (xfer->rx_buf != NULL && (sdd->state & RXBUSY)) - sdd->ops->stop(sdd->rx_ch); + sdd->ops->stop(sdd->rx_dma.ch); } goto out; @@ -741,25 +770,6 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, msg->complete(msg->context); } -static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) -{ - - struct samsung_dma_info info; - sdd->ops = samsung_dma_get_ops(); - - info.cap = DMA_SLAVE; - info.client = &s3c64xx_spi_dma_client; - info.direction = DMA_FROM_DEVICE; - info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; - info.width = sdd->cur_bpw / 8; - sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info); - info.direction = DMA_TO_DEVICE; - info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; - sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info); - - return 1; -} - static void s3c64xx_spi_work(struct work_struct *work) { struct s3c64xx_spi_driver_data *sdd = container_of(work, @@ -796,8 +806,8 @@ static void s3c64xx_spi_work(struct work_struct *work) spin_unlock_irqrestore(&sdd->lock, flags); /* Free DMA channels */ - sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client); - sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client); + sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client); + sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client); } static int s3c64xx_spi_transfer(struct spi_device *spi, @@ -1014,8 +1024,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) sdd->cntrlr_info = sci; sdd->pdev = pdev; sdd->sfr_start = mem_res->start; - sdd->tx_dmach = dmatx_res->start; - sdd->rx_dmach = dmarx_res->start; + sdd->tx_dma.dmach = dmatx_res->start; + sdd->tx_dma.direction = DMA_TO_DEVICE; + sdd->rx_dma.dmach = dmarx_res->start; + sdd->rx_dma.direction = DMA_FROM_DEVICE; sdd->cur_bpw = 8; @@ -1103,7 +1115,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) pdev->id, master->num_chipselect); dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n", mem_res->end, mem_res->start, - sdd->rx_dmach, sdd->tx_dmach); + sdd->rx_dma.dmach, sdd->tx_dma.dmach); return 0; From 344b4c48887a443f7478fc7047d1397b20821ed3 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:43 +0900 Subject: [PATCH 0364/1596] ASoC: Samsung: Update DMA interface This patch adds to support the DMA PL330 driver that uses DMA generic API. Samsung sound driver uses DMA generic API if architecture supports it. Otherwise, use samsung specific S3C-PL330 API driver to transfer PCM data. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Cc: Jassi Brar Cc: Liam Girdwood Acked-by: Mark Brown [kgene.kim@samsung.com: removed useless variable] Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/mach-s3c2410/include/mach/dma.h | 10 +- arch/arm/mach-s3c64xx/include/mach/dma.h | 2 +- .../arm/plat-samsung/include/plat/dma-pl330.h | 2 +- sound/soc/samsung/ac97.c | 10 +- sound/soc/samsung/dma.c | 146 +++++++----------- sound/soc/samsung/dma.h | 4 +- 6 files changed, 78 insertions(+), 96 deletions(-) diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h index e61a91f88c52..4e485bab66de 100644 --- a/arch/arm/mach-s3c2410/include/mach/dma.h +++ b/arch/arm/mach-s3c2410/include/mach/dma.h @@ -50,6 +50,11 @@ enum dma_ch { DMACH_MAX, /* the end entry */ }; +static inline bool samsung_dma_has_circular(void) +{ + return false; +} + static inline bool samsung_dma_is_dmadev(void) { return false; @@ -202,9 +207,4 @@ struct s3c2410_dma_chan { typedef unsigned long dma_device_t; -static inline bool s3c_dma_has_circular(void) -{ - return false; -} - #endif /* __ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 49c3a53135d4..74fdf25c9042 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -58,7 +58,7 @@ enum dma_ch { DMACH_MAX /* the end */ }; -static __inline__ bool s3c_dma_has_circular(void) +static inline bool samsung_dma_has_circular(void) { return true; } diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h index 9a1dadb0218e..2e55e5958674 100644 --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -89,7 +89,7 @@ struct s3c2410_dma_client { char *name; }; -static inline bool s3c_dma_has_circular(void) +static inline bool samsung_dma_has_circular(void) { return true; } diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index f97110e72e85..b4f9b0003685 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -271,7 +271,10 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); + if (!dma_data->ops) + dma_data->ops = samsung_dma_get_ops(); + + dma_data->ops->started(dma_data->channel); return 0; } @@ -317,7 +320,10 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); + if (!dma_data->ops) + dma_data->ops = samsung_dma_get_ops(); + + dma_data->ops->started(dma_data->channel); return 0; } diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 9465588b02f2..851346f7d68d 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -54,7 +54,6 @@ struct runtime_data { spinlock_t lock; int state; unsigned int dma_loaded; - unsigned int dma_limit; unsigned int dma_period; dma_addr_t dma_start; dma_addr_t dma_pos; @@ -62,77 +61,79 @@ struct runtime_data { struct s3c_dma_params *params; }; +static void audio_buffdone(void *data); + /* dma_enqueue * * place a dma buffer onto the queue for the dma system * to handle. -*/ + */ static void dma_enqueue(struct snd_pcm_substream *substream) { struct runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; unsigned int limit; - int ret; + struct samsung_dma_prep_info dma_info; pr_debug("Entered %s\n", __func__); - if (s3c_dma_has_circular()) - limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; - else - limit = prtd->dma_limit; + limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit); - while (prtd->dma_loaded < limit) { - unsigned long len = prtd->dma_period; + dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); + dma_info.direction = + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + dma_info.fp = audio_buffdone; + dma_info.fp_param = substream; + dma_info.period = prtd->dma_period; + dma_info.len = prtd->dma_period*limit; + while (prtd->dma_loaded < limit) { pr_debug("dma_loaded: %d\n", prtd->dma_loaded); - if ((pos + len) > prtd->dma_end) { - len = prtd->dma_end - pos; - pr_debug("%s: corrected dma len %ld\n", __func__, len); + if ((pos + dma_info.period) > prtd->dma_end) { + dma_info.period = prtd->dma_end - pos; + pr_debug("%s: corrected dma len %ld\n", + __func__, dma_info.period); } - ret = s3c2410_dma_enqueue(prtd->params->channel, - substream, pos, len); + dma_info.buf = pos; + prtd->params->ops->prepare(prtd->params->ch, &dma_info); - if (ret == 0) { - prtd->dma_loaded++; - pos += prtd->dma_period; - if (pos >= prtd->dma_end) - pos = prtd->dma_start; - } else - break; + prtd->dma_loaded++; + pos += prtd->dma_period; + if (pos >= prtd->dma_end) + pos = prtd->dma_start; } prtd->dma_pos = pos; } -static void audio_buffdone(struct s3c2410_dma_chan *channel, - void *dev_id, int size, - enum s3c2410_dma_buffresult result) +static void audio_buffdone(void *data) { - struct snd_pcm_substream *substream = dev_id; - struct runtime_data *prtd; + struct snd_pcm_substream *substream = data; + struct runtime_data *prtd = substream->runtime->private_data; pr_debug("Entered %s\n", __func__); - if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) - return; - - prtd = substream->runtime->private_data; + if (prtd->state & ST_RUNNING) { + prtd->dma_pos += prtd->dma_period; + if (prtd->dma_pos >= prtd->dma_end) + prtd->dma_pos = prtd->dma_start; - if (substream) - snd_pcm_period_elapsed(substream); + if (substream) + snd_pcm_period_elapsed(substream); - spin_lock(&prtd->lock); - if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { - prtd->dma_loaded--; - dma_enqueue(substream); + spin_lock(&prtd->lock); + if (!samsung_dma_has_circular()) { + prtd->dma_loaded--; + dma_enqueue(substream); + } + spin_unlock(&prtd->lock); } - - spin_unlock(&prtd->lock); } static int dma_hw_params(struct snd_pcm_substream *substream, @@ -144,8 +145,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream, unsigned long totbytes = params_buffer_bytes(params); struct s3c_dma_params *dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - int ret = 0; - + struct samsung_dma_info dma_info; pr_debug("Entered %s\n", __func__); @@ -163,30 +163,26 @@ static int dma_hw_params(struct snd_pcm_substream *substream, pr_debug("params %p, client %p, channel %d\n", prtd->params, prtd->params->client, prtd->params->channel); - ret = s3c2410_dma_request(prtd->params->channel, - prtd->params->client, NULL); - - if (ret < 0) { - printk(KERN_ERR "failed to get dma channel\n"); - return ret; - } - - /* use the circular buffering if we have it available. */ - if (s3c_dma_has_circular()) - s3c2410_dma_setflags(prtd->params->channel, - S3C2410_DMAF_CIRCULAR); + prtd->params->ops = samsung_dma_get_ops(); + + dma_info.cap = (samsung_dma_has_circular() ? + DMA_CYCLIC : DMA_SLAVE); + dma_info.client = prtd->params->client; + dma_info.direction = + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + dma_info.width = prtd->params->dma_size; + dma_info.fifo = prtd->params->dma_addr; + prtd->params->ch = prtd->params->ops->request( + prtd->params->channel, &dma_info); } - s3c2410_dma_set_buffdone_fn(prtd->params->channel, - audio_buffdone); - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totbytes; spin_lock_irq(&prtd->lock); prtd->dma_loaded = 0; - prtd->dma_limit = runtime->hw.periods_min; prtd->dma_period = params_period_bytes(params); prtd->dma_start = runtime->dma_addr; prtd->dma_pos = prtd->dma_start; @@ -206,7 +202,8 @@ static int dma_hw_free(struct snd_pcm_substream *substream) snd_pcm_set_runtime_buffer(substream, NULL); if (prtd->params) { - s3c2410_dma_free(prtd->params->channel, prtd->params->client); + prtd->params->ops->release(prtd->params->ch, + prtd->params->client); prtd->params = NULL; } @@ -225,23 +222,9 @@ static int dma_prepare(struct snd_pcm_substream *substream) if (!prtd->params) return 0; - /* channel needs configuring for mem=>device, increment memory addr, - * sync to pclk, half-word transfers to the IIS-FIFO. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - s3c2410_dma_devconfig(prtd->params->channel, - S3C2410_DMASRC_MEM, - prtd->params->dma_addr); - } else { - s3c2410_dma_devconfig(prtd->params->channel, - S3C2410_DMASRC_HW, - prtd->params->dma_addr); - } - - s3c2410_dma_config(prtd->params->channel, - prtd->params->dma_size); - /* flush the DMA channel */ - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); + prtd->params->ops->flush(prtd->params->ch); + prtd->dma_loaded = 0; prtd->dma_pos = prtd->dma_start; @@ -265,14 +248,14 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: prtd->state |= ST_RUNNING; - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); + prtd->params->ops->trigger(prtd->params->ch); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: prtd->state &= ~ST_RUNNING; - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP); + prtd->params->ops->stop(prtd->params->ch); break; default: @@ -291,21 +274,12 @@ dma_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct runtime_data *prtd = runtime->private_data; unsigned long res; - dma_addr_t src, dst; pr_debug("Entered %s\n", __func__); - spin_lock(&prtd->lock); - s3c2410_dma_getposition(prtd->params->channel, &src, &dst); - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - res = dst - prtd->dma_start; - else - res = src - prtd->dma_start; - - spin_unlock(&prtd->lock); + res = prtd->dma_pos - prtd->dma_start; - pr_debug("Pointer %x %x\n", src, dst); + pr_debug("Pointer offset: %lu\n", res); /* we seem to be getting the odd error from the pcm library due * to out-of-bounds pointers. this is maybe due to the dma engine diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index c50659269a40..7d1ead77ef21 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -6,7 +6,7 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * - * ALSA PCM interface for the Samsung S3C24xx CPU + * ALSA PCM interface for the Samsung SoC */ #ifndef _S3C_AUDIO_H @@ -17,6 +17,8 @@ struct s3c_dma_params { int channel; /* Channel ID */ dma_addr_t dma_addr; int dma_size; /* Size of the DMA transfer */ + unsigned ch; + struct samsung_dma_ops *ops; }; #endif From 51ddf31da16b1ab9da861eafedad6d263faf4388 Mon Sep 17 00:00:00 2001 From: Boojin Kim Date: Fri, 2 Sep 2011 09:44:44 +0900 Subject: [PATCH 0365/1596] ARM: SAMSUNG: Remove Samsung specific enum type for dma direction This patch removes the samsung specific enum type 's3c2410_dmasrc' and uses 'dma_data_direction' instead. Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Signed-off-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/mach-s3c2410/include/mach/dma.h | 2 +- arch/arm/mach-s3c2412/dma.c | 4 ++-- arch/arm/mach-s3c64xx/dma.c | 10 +++++----- arch/arm/mach-s3c64xx/include/mach/dma.h | 2 +- arch/arm/plat-s3c24xx/dma.c | 10 +++++----- arch/arm/plat-samsung/include/plat/dma-s3c24xx.h | 2 +- arch/arm/plat-samsung/include/plat/dma.h | 9 +++------ arch/arm/plat-samsung/s3c-dma-ops.c | 5 +---- drivers/mmc/host/s3cmci.c | 6 +++--- 9 files changed, 22 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h index 4e485bab66de..ae8e482b6427 100644 --- a/arch/arm/mach-s3c2410/include/mach/dma.h +++ b/arch/arm/mach-s3c2410/include/mach/dma.h @@ -174,7 +174,7 @@ struct s3c2410_dma_chan { struct s3c2410_dma_client *client; /* channel configuration */ - enum s3c2410_dmasrc source; + enum dma_data_direction source; enum dma_ch req_ch; unsigned long dev_addr; unsigned long load_timeout; diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c index 7abecfca0b7e..b4fc3ba367d6 100644 --- a/arch/arm/mach-s3c2412/dma.c +++ b/arch/arm/mach-s3c2412/dma.c @@ -148,11 +148,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = { static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan, struct s3c24xx_dma_map *map, - enum s3c2410_dmasrc dir) + enum dma_data_direction dir) { unsigned long chsel; - if (dir == S3C2410_DMASRC_HW) + if (dir == DMA_FROM_DEVICE) chsel = map->channels_rx[0]; else chsel = map->channels[0]; diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c index 204bfafe4bfc..67c97fab62fd 100644 --- a/arch/arm/mach-s3c64xx/dma.c +++ b/arch/arm/mach-s3c64xx/dma.c @@ -147,14 +147,14 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan, u32 control0, control1; switch (chan->source) { - case S3C2410_DMASRC_HW: + case DMA_FROM_DEVICE: src = chan->dev_addr; dst = data; control0 = PL080_CONTROL_SRC_AHB2; control0 |= PL080_CONTROL_DST_INCR; break; - case S3C2410_DMASRC_MEM: + case DMA_TO_DEVICE: src = data; dst = chan->dev_addr; control0 = PL080_CONTROL_DST_AHB2; @@ -416,7 +416,7 @@ EXPORT_SYMBOL(s3c2410_dma_enqueue); int s3c2410_dma_devconfig(enum dma_ch channel, - enum s3c2410_dmasrc source, + enum dma_data_direction source, unsigned long devaddr) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -437,11 +437,11 @@ int s3c2410_dma_devconfig(enum dma_ch channel, pr_debug("%s: peripheral %d\n", __func__, peripheral); switch (source) { - case S3C2410_DMASRC_HW: + case DMA_FROM_DEVICE: config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT; config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT; break; - case S3C2410_DMASRC_MEM: + case DMA_TO_DEVICE: config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT; config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT; break; diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 74fdf25c9042..fe1a98cf0e4c 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -99,7 +99,7 @@ struct s3c2410_dma_chan { unsigned char peripheral; unsigned int flags; - enum s3c2410_dmasrc source; + enum dma_data_direction source; dma_addr_t dev_addr; diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 539bd0e3defd..53754bcf15a7 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -1094,14 +1094,14 @@ EXPORT_SYMBOL(s3c2410_dma_config); * * configure the dma source/destination hardware type and address * - * source: S3C2410_DMASRC_HW: source is hardware - * S3C2410_DMASRC_MEM: source is memory + * source: DMA_FROM_DEVICE: source is hardware + * DMA_TO_DEVICE: source is memory * * devaddr: physical address of the source */ int s3c2410_dma_devconfig(enum dma_ch channel, - enum s3c2410_dmasrc source, + enum dma_data_direction source, unsigned long devaddr) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); @@ -1131,7 +1131,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel, hwcfg |= S3C2410_DISRCC_INC; switch (source) { - case S3C2410_DMASRC_HW: + case DMA_FROM_DEVICE: /* source is hardware */ pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", __func__, devaddr, hwcfg); @@ -1142,7 +1142,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel, chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); break; - case S3C2410_DMASRC_MEM: + case DMA_TO_DEVICE: /* source is memory */ pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n", __func__, devaddr, hwcfg); diff --git a/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h index 336d5ac02035..19828296a562 100644 --- a/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h +++ b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h @@ -47,7 +47,7 @@ struct s3c24xx_dma_selection { void (*direction)(struct s3c2410_dma_chan *chan, struct s3c24xx_dma_map *map, - enum s3c2410_dmasrc dir); + enum dma_data_direction dir); }; extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h index 361076060744..b9061128abde 100644 --- a/arch/arm/plat-samsung/include/plat/dma.h +++ b/arch/arm/plat-samsung/include/plat/dma.h @@ -10,17 +10,14 @@ * published by the Free Software Foundation. */ +#include + enum s3c2410_dma_buffresult { S3C2410_RES_OK, S3C2410_RES_ERR, S3C2410_RES_ABORT }; -enum s3c2410_dmasrc { - S3C2410_DMASRC_HW, /* source is memory */ - S3C2410_DMASRC_MEM /* source is hardware */ -}; - /* enum s3c2410_chan_op * * operation codes passed to the DMA code by the user, and also used @@ -112,7 +109,7 @@ extern int s3c2410_dma_config(enum dma_ch channel, int xferunit); */ extern int s3c2410_dma_devconfig(enum dma_ch channel, - enum s3c2410_dmasrc source, unsigned long devaddr); + enum dma_data_direction source, unsigned long devaddr); /* s3c2410_dma_getposition * diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c index 33ab3241268d..582333c70585 100644 --- a/arch/arm/plat-samsung/s3c-dma-ops.c +++ b/arch/arm/plat-samsung/s3c-dma-ops.c @@ -48,10 +48,7 @@ static unsigned s3c_dma_request(enum dma_ch dma_ch, data->ch = dma_ch; list_add_tail(&data->node, &dma_list); - if (info->direction == DMA_FROM_DEVICE) - s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW, info->fifo); - else - s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM, info->fifo); + s3c2410_dma_devconfig(dma_ch, info->direction, info->fifo); if (info->cap == DMA_CYCLIC) s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index a04f87d7ee3d..03cfdab99c8f 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -913,9 +913,9 @@ static void finalize_request(struct s3cmci_host *host) } static void s3cmci_dma_setup(struct s3cmci_host *host, - enum s3c2410_dmasrc source) + enum dma_data_direction source) { - static enum s3c2410_dmasrc last_source = -1; + static enum dma_data_direction last_source = -1; static int setup_ok; if (last_source == source) @@ -1087,7 +1087,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW); + s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, From 27a84d54c02591e815d291ae0ee4bfb9cfd21065 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 15 Sep 2011 14:01:40 +0200 Subject: [PATCH 0366/1596] block: refactor generic_make_request Move all the checks performed on a bio into a new helper, and call it as soon as bio is submitted even if it is a re-submission from ->make_request. We explicitly mark the new helper as beeing non-inlined as the stack usage for printing the block device name in the failure case is quite high and this a patch where we have to be extremely conservative about stack usage. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- block/blk-core.c | 95 +++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index f58e019be67b..684d7eb33d43 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1412,31 +1412,8 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors) return 0; } -/** - * generic_make_request - hand a buffer to its device driver for I/O - * @bio: The bio describing the location in memory and on the device. - * - * generic_make_request() is used to make I/O requests of block - * devices. It is passed a &struct bio, which describes the I/O that needs - * to be done. - * - * generic_make_request() does not return any status. The - * success/failure status of the request, along with notification of - * completion, is delivered asynchronously through the bio->bi_end_io - * function described (one day) else where. - * - * The caller of generic_make_request must make sure that bi_io_vec - * are set to describe the memory buffer, and that bi_dev and bi_sector are - * set to describe the device address, and the - * bi_end_io and optionally bi_private are set to describe how - * completion notification should be signaled. - * - * generic_make_request and the drivers it calls may use bi_next if this - * bio happens to be merged with someone else, and may change bi_dev and - * bi_sector for remaps as it sees fit. So the values of these fields - * should NOT be depended on after the call to generic_make_request. - */ -static inline void __generic_make_request(struct bio *bio) +static noinline_for_stack bool +generic_make_request_checks(struct bio *bio) { struct request_queue *q; int nr_sectors = bio_sectors(bio); @@ -1515,35 +1492,62 @@ static inline void __generic_make_request(struct bio *bio) /* if bio = NULL, bio has been throttled and will be submitted later. */ if (!bio) - return; + return false; + trace_block_bio_queue(q, bio); - q->make_request_fn(q, bio); - return; + return true; end_io: bio_endio(bio, err); + return false; } -/* - * We only want one ->make_request_fn to be active at a time, - * else stack usage with stacked devices could be a problem. - * So use current->bio_list to keep a list of requests - * submited by a make_request_fn function. - * current->bio_list is also used as a flag to say if - * generic_make_request is currently active in this task or not. - * If it is NULL, then no make_request is active. If it is non-NULL, - * then a make_request is active, and new requests should be added - * at the tail +/** + * generic_make_request - hand a buffer to its device driver for I/O + * @bio: The bio describing the location in memory and on the device. + * + * generic_make_request() is used to make I/O requests of block + * devices. It is passed a &struct bio, which describes the I/O that needs + * to be done. + * + * generic_make_request() does not return any status. The + * success/failure status of the request, along with notification of + * completion, is delivered asynchronously through the bio->bi_end_io + * function described (one day) else where. + * + * The caller of generic_make_request must make sure that bi_io_vec + * are set to describe the memory buffer, and that bi_dev and bi_sector are + * set to describe the device address, and the + * bi_end_io and optionally bi_private are set to describe how + * completion notification should be signaled. + * + * generic_make_request and the drivers it calls may use bi_next if this + * bio happens to be merged with someone else, and may resubmit the bio to + * a lower device by calling into generic_make_request recursively, which + * means the bio should NOT be touched after the call to ->make_request_fn. */ void generic_make_request(struct bio *bio) { struct bio_list bio_list_on_stack; + if (!generic_make_request_checks(bio)) + return; + + /* + * We only want one ->make_request_fn to be active at a time, else + * stack usage with stacked devices could be a problem. So use + * current->bio_list to keep a list of requests submited by a + * make_request_fn function. current->bio_list is also used as a + * flag to say if generic_make_request is currently active in this + * task or not. If it is NULL, then no make_request is active. If + * it is non-NULL, then a make_request is active, and new requests + * should be added at the tail + */ if (current->bio_list) { - /* make_request is active */ bio_list_add(current->bio_list, bio); return; } + /* following loop may be a bit non-obvious, and so deserves some * explanation. * Before entering the loop, bio->bi_next is NULL (as all callers @@ -1551,22 +1555,21 @@ void generic_make_request(struct bio *bio) * We pretend that we have just taken it off a longer list, so * we assign bio_list to a pointer to the bio_list_on_stack, * thus initialising the bio_list of new bios to be - * added. __generic_make_request may indeed add some more bios + * added. ->make_request() may indeed add some more bios * through a recursive call to generic_make_request. If it * did, we find a non-NULL value in bio_list and re-enter the loop * from the top. In this case we really did just take the bio * of the top of the list (no pretending) and so remove it from - * bio_list, and call into __generic_make_request again. - * - * The loop was structured like this to make only one call to - * __generic_make_request (which is important as it is large and - * inlined) and to keep the structure simple. + * bio_list, and call into ->make_request() again. */ BUG_ON(bio->bi_next); bio_list_init(&bio_list_on_stack); current->bio_list = &bio_list_on_stack; do { - __generic_make_request(bio); + struct request_queue *q = bdev_get_queue(bio->bi_bdev); + + q->make_request_fn(q, bio); + bio = bio_list_pop(current->bio_list); } while (bio); current->bio_list = NULL; /* deactivate */ From 986afc98ce24901865828dab9ba876fd9be6beb2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 12 Aug 2011 18:08:17 +0900 Subject: [PATCH 0367/1596] ARM: S3C64XX: Hook up GPIO initiated DVS on Cragganmore Allow us to ramp VDDARM quickly by using a GPIO to signal a voltage change instead of doing a register write. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/mach-crag6410.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index af0c2fe1ea37..5affb26a1985 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -353,6 +353,12 @@ static struct pca953x_platform_data crag6410_pca_data = { .irq_base = 0, }; +/* VDDARM is controlled by DVS1 connected to GPK(0) */ +static struct wm831x_buckv_pdata vddarm_pdata = { + .dvs_control_src = 1, + .dvs_gpio = S3C64XX_GPK(0), +}; + static struct regulator_consumer_supply vddarm_consumers[] __initdata = { REGULATOR_SUPPLY("vddarm", NULL), }; @@ -368,6 +374,7 @@ static struct regulator_init_data vddarm __initdata = { .num_consumer_supplies = ARRAY_SIZE(vddarm_consumers), .consumer_supplies = vddarm_consumers, .supply_regulator = "WALLVDD", + .driver_data = &vddarm_pdata, }; static struct regulator_init_data vddint __initdata = { @@ -503,6 +510,8 @@ static struct wm831x_pdata crag_pmic_pdata __initdata = { .backup = &banff_backup_pdata, .gpio_defaults = { + /* GPIO5: DVS1_REQ - CMOS, DBVDD, active high */ + [4] = WM831X_GPN_DIR | WM831X_GPN_POL | WM831X_GPN_ENA | 0x8, /* GPIO11: Touchscreen data - CMOS, DBVDD, active high*/ [10] = WM831X_GPN_POL | WM831X_GPN_ENA | 0x6, /* GPIO12: Touchscreen pen down - CMOS, DBVDD, active high*/ From fad23ddac36920600e2457cf540c4d6383290cd2 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Mon, 19 Sep 2011 10:27:19 +0900 Subject: [PATCH 0368/1596] ARM: EXYNOS4: register the second instance of pl330 DMAC Platform data is provided for two instance of pl330 DMAC, but only one DMAC is register with amba_device. This patch register the second instance. Signed-off-by: Alim Akhtar Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-exynos4/dma.c b/arch/arm/mach-exynos4/dma.c index d57d66255021..9667c61e64fb 100644 --- a/arch/arm/mach-exynos4/dma.c +++ b/arch/arm/mach-exynos4/dma.c @@ -243,6 +243,7 @@ struct amba_device exynos4_device_pdma1 = { static int __init exynos4_dma_init(void) { amba_device_register(&exynos4_device_pdma0, &iomem_resource); + amba_device_register(&exynos4_device_pdma1, &iomem_resource); return 0; } From f86147cc8faca81de5edfa1fab07b119c1867322 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Mon, 19 Sep 2011 10:27:23 +0900 Subject: [PATCH 0369/1596] ARM: S5PV210: register the second instance of pl330 DMAC Platform data is provided for two instance of pl330 DMAC, but only one DMAC is register with amba_device. This patch register the second instance. Signed-off-by: Alim Akhtar Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv210/dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-s5pv210/dma.c b/arch/arm/mach-s5pv210/dma.c index f79d0b06cbf9..86b749c18b77 100644 --- a/arch/arm/mach-s5pv210/dma.c +++ b/arch/arm/mach-s5pv210/dma.c @@ -254,6 +254,7 @@ struct amba_device s5pv210_device_pdma1 = { static int __init s5pv210_dma_init(void) { amba_device_register(&s5pv210_device_pdma0, &iomem_resource); + amba_device_register(&s5pv210_device_pdma1, &iomem_resource); return 0; } From d5663e7a404ae97888bb8e7a7376de3fb0878ddd Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Mon, 19 Sep 2011 10:27:26 +0900 Subject: [PATCH 0370/1596] ARM: S5PC100: register the second instance of pl330 DMAC Platform data is provided for two instance of pl330 DMAC, but only one DMAC is register with amba_device. This patch register the second instance. Signed-off-by: Alim Akhtar Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pc100/dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-s5pc100/dma.c b/arch/arm/mach-s5pc100/dma.c index ef803e92d35d..065a087f5a8b 100644 --- a/arch/arm/mach-s5pc100/dma.c +++ b/arch/arm/mach-s5pc100/dma.c @@ -260,6 +260,7 @@ struct amba_device s5pc100_device_pdma1 = { static int __init s5pc100_dma_init(void) { amba_device_register(&s5pc100_device_pdma0, &iomem_resource); + amba_device_register(&s5pc100_device_pdma1, &iomem_resource); return 0; } From 937bb6e4c676fecbfbc1939b942241c3f27bf5d8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 24 Jun 2011 13:56:15 +0200 Subject: [PATCH 0371/1596] serial: sh-sci: don't filter on DMA device, use only channel ID On some sh-mobile systems there are more than one DMA controllers, that can be used for serial ports. Specifying a DMA device in sh-sci platform data unnecessarily restricts the driver to only use one DMA controller. Signed-off-by: Guennadi Liakhovetski [Fixed the trivial conflict in include/linux/serial_sci.h] Signed-off-by: Vinod Koul --- drivers/tty/serial/sh-sci.c | 25 ++++++++----------------- include/linux/serial_sci.h | 2 -- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index a9414facda47..dbd32a1286d3 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1439,12 +1439,8 @@ static bool filter(struct dma_chan *chan, void *slave) dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, param->slave_id); - if (param->dma_dev == chan->device->dev) { - chan->private = param; - return true; - } else { - return false; - } + chan->private = param; + return true; } static void rx_timer_fn(unsigned long arg) @@ -1470,10 +1466,10 @@ static void sci_request_dma(struct uart_port *port) dma_cap_mask_t mask; int nent; - dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__, - port->line, s->cfg->dma_dev); + dev_dbg(port->dev, "%s: port %d\n", __func__, + port->line); - if (!s->cfg->dma_dev) + if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0) return; dma_cap_zero(mask); @@ -1483,7 +1479,6 @@ static void sci_request_dma(struct uart_port *port) /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ param->slave_id = s->cfg->dma_slave_tx; - param->dma_dev = s->cfg->dma_dev; s->cookie_tx = -EINVAL; chan = dma_request_channel(mask, filter, param); @@ -1512,7 +1507,6 @@ static void sci_request_dma(struct uart_port *port) /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ param->slave_id = s->cfg->dma_slave_rx; - param->dma_dev = s->cfg->dma_dev; chan = dma_request_channel(mask, filter, param); dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); @@ -1557,9 +1551,6 @@ static void sci_free_dma(struct uart_port *port) { struct sci_port *s = to_sci_port(port); - if (!s->cfg->dma_dev) - return; - if (s->chan_tx) sci_tx_dma_release(s, false); if (s->chan_rx) @@ -1967,9 +1958,9 @@ static int __devinit sci_init_single(struct platform_device *dev, port->serial_in = sci_serial_in; port->serial_out = sci_serial_out; - if (p->dma_dev) - dev_dbg(port->dev, "DMA device %p, tx %d, rx %d\n", - p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); + if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) + dev_dbg(port->dev, "DMA tx %d, rx %d\n", + p->dma_slave_tx, p->dma_slave_rx); return 0; } diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index 8bffe9ae2ca0..0efa1f10bc2b 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -131,8 +131,6 @@ struct plat_sci_port { struct plat_sci_port_ops *ops; - struct device *dma_dev; - unsigned int dma_slave_tx; unsigned int dma_slave_rx; }; From d0f0b43f78b88b42e795e4c28f3591cb57590692 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 19 Aug 2011 22:40:07 +0900 Subject: [PATCH 0372/1596] ARM: S3C64XX: Use module identification for Cragganmore system builds The Cragganmore system is modular with I2C based identification chips on the system allowing identification of the system build. Provide a stub I2C driver which parses the module IDs and uses them to select the appropriate audio subsystem components to register. To avoid confusion due to having the mini-driver in the system the driver is placed in a separate file. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/Kconfig | 1 + arch/arm/mach-s3c64xx/Makefile | 2 +- arch/arm/mach-s3c64xx/include/mach/crag6410.h | 23 +++ arch/arm/mach-s3c64xx/mach-crag6410-module.c | 173 ++++++++++++++++++ arch/arm/mach-s3c64xx/mach-crag6410.c | 85 +-------- 5 files changed, 203 insertions(+), 81 deletions(-) create mode 100644 arch/arm/mach-s3c64xx/include/mach/crag6410.h create mode 100644 arch/arm/mach-s3c64xx/mach-crag6410-module.c diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index f057b6ae4f90..5552e048c2be 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -288,5 +288,6 @@ config MACH_WLF_CRAGG_6410 select S3C_DEV_RTC select S3C64XX_DEV_SPI select S3C24XX_GPIO_EXTRA128 + select I2C help Machine support for the Wolfson Cragganmore S3C6410 variant. diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 61b4034a0c22..5fdea6aa50d4 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -55,7 +55,7 @@ obj-$(CONFIG_MACH_HMT) += mach-hmt.o obj-$(CONFIG_MACH_SMARTQ) += mach-smartq.o obj-$(CONFIG_MACH_SMARTQ5) += mach-smartq5.o obj-$(CONFIG_MACH_SMARTQ7) += mach-smartq7.o -obj-$(CONFIG_MACH_WLF_CRAGG_6410) += mach-crag6410.o +obj-$(CONFIG_MACH_WLF_CRAGG_6410) += mach-crag6410.o mach-crag6410-module.o # device support diff --git a/arch/arm/mach-s3c64xx/include/mach/crag6410.h b/arch/arm/mach-s3c64xx/include/mach/crag6410.h new file mode 100644 index 000000000000..be9074e17dfd --- /dev/null +++ b/arch/arm/mach-s3c64xx/include/mach/crag6410.h @@ -0,0 +1,23 @@ +/* Cragganmore 6410 shared definitions + * + * Copyright 2011 Wolfson Microelectronics plc + * Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef MACH_CRAG6410_H +#define MACH_CRAG6410_H + +#include + +#define BANFF_PMIC_IRQ_BASE IRQ_BOARD_START +#define GLENFARCLAS_PMIC_IRQ_BASE (IRQ_BOARD_START + 64) + +#define PCA935X_GPIO_BASE GPIO_BOARD_START +#define CODEC_GPIO_BASE (GPIO_BOARD_START + 8) +#define GLENFARCLAS_PMIC_GPIO_BASE (GPIO_BOARD_START + 16) + +#endif diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c new file mode 100644 index 000000000000..0708fa01db9c --- /dev/null +++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -0,0 +1,173 @@ +/* Speyside modules for Cragganmore - board data probing + * + * Copyright 2011 Wolfson Microelectronics plc + * Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +static struct wm8996_retune_mobile_config wm8996_retune[] = { + { + .name = "Sub LPF", + .rate = 48000, + .regs = { + 0x6318, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000, + 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000, + 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000 + }, + }, + { + .name = "Sub HPF", + .rate = 48000, + .regs = { + 0x000A, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000, + 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000, + 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000 + }, + }, +}; + +static struct wm8996_pdata wm8996_pdata __initdata = { + .ldo_ena = S3C64XX_GPN(7), + .gpio_base = CODEC_GPIO_BASE, + .micdet_def = 1, + .inl_mode = WM8996_DIFFERRENTIAL_1, + .inr_mode = WM8996_DIFFERRENTIAL_1, + + .irq_flags = IRQF_TRIGGER_RISING, + + .gpio_default = { + 0x8001, /* GPIO1 == ADCLRCLK1 */ + 0x8001, /* GPIO2 == ADCLRCLK2, input due to CPU */ + 0x0141, /* GPIO3 == HP_SEL */ + 0x0002, /* GPIO4 == IRQ */ + 0x020e, /* GPIO5 == CLKOUT */ + }, + + .retune_mobile_cfgs = wm8996_retune, + .num_retune_mobile_cfgs = ARRAY_SIZE(wm8996_retune), +}; + +static struct wm8962_pdata wm8962_pdata __initdata = { + .gpio_init = { + 0, + WM8962_GPIO_FN_OPCLK, + WM8962_GPIO_FN_DMICCLK, + 0, + 0x8000 | WM8962_GPIO_FN_DMICDAT, + WM8962_GPIO_FN_IRQ, /* Open drain mode */ + }, + .irq_active_low = true, +}; + +static struct wm9081_pdata wm9081_pdata __initdata = { + .irq_high = false, + .irq_cmos = false, +}; + +static const struct i2c_board_info wm1254_devs[] = { + { I2C_BOARD_INFO("wm8996", 0x1a), + .platform_data = &wm8996_pdata, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, + }, + { I2C_BOARD_INFO("wm9081", 0x6c), + .platform_data = &wm9081_pdata, }, +}; + +static const struct i2c_board_info wm1259_devs[] = { + { I2C_BOARD_INFO("wm8962", 0x1a), + .platform_data = &wm8962_pdata, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, + }, +}; + + +static __devinitdata const struct { + u8 id; + const char *name; + const struct i2c_board_info *i2c_devs; + int num_i2c_devs; +} gf_mods[] = { + { .id = 0x01, .name = "1250-EV1 Springbank" }, + { .id = 0x02, .name = "1251-EV1 Jura" }, + { .id = 0x03, .name = "1252-EV1 Glenlivet" }, + { .id = 0x11, .name = "6249-EV2 Glenfarclas", }, + { .id = 0x21, .name = "1275-EV1 Mortlach" }, + { .id = 0x25, .name = "1274-EV1 Glencadam" }, + { .id = 0x31, .name = "1253-EV1 Tomatin", }, + { .id = 0x39, .name = "1254-EV1 Dallas Dhu", + .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) }, + { .id = 0x3a, .name = "1259-EV1 Tobermory", + .i2c_devs = wm1259_devs, .num_i2c_devs = ARRAY_SIZE(wm1259_devs) }, + { .id = 0x3b, .name = "1255-EV1 Kilchoman" }, + { .id = 0x3c, .name = "1273-EV1 Longmorn" }, +}; + +static __devinit int wlf_gf_module_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) +{ + int ret, i, j, id, rev; + + ret = i2c_smbus_read_byte_data(i2c, 0); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read ID: %d\n", ret); + return ret; + } + + id = (ret & 0xfe) >> 2; + rev = ret & 0x3; + for (i = 0; i < ARRAY_SIZE(gf_mods); i++) + if (id == gf_mods[i].id) + break; + + if (i < ARRAY_SIZE(gf_mods)) { + dev_info(&i2c->dev, "%s revision %d\n", + gf_mods[i].name, rev + 1); + for (j = 0; j < gf_mods[i].num_i2c_devs; j++) { + if (!i2c_new_device(i2c->adapter, + &(gf_mods[i].i2c_devs[j]))) + dev_err(&i2c->dev, + "Failed to register dev: %d\n", ret); + } + } else { + dev_warn(&i2c->dev, "Unknown module ID %d revision %d\n", + id, rev); + } + + return 0; +} + +static const struct i2c_device_id wlf_gf_module_id[] = { + { "wlf-gf-module", 0 }, + { } +}; + +static struct i2c_driver wlf_gf_module_driver = { + .driver = { + .name = "wlf-gf-module", + .owner = THIS_MODULE, + }, + .probe = wlf_gf_module_probe, + .id_table = wlf_gf_module_id, +}; + +static int __init wlf_gf_module_register(void) +{ + return i2c_add_driver(&wlf_gf_module_driver); +} +module_init(wlf_gf_module_register); diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 5affb26a1985..1ef53b28f683 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -65,17 +66,6 @@ #include #include -#include -#include -#include - -#define BANFF_PMIC_IRQ_BASE IRQ_BOARD_START -#define GLENFARCLAS_PMIC_IRQ_BASE (IRQ_BOARD_START + 64) - -#define PCA935X_GPIO_BASE GPIO_BOARD_START -#define CODEC_GPIO_BASE (GPIO_BOARD_START + 8) -#define GLENFARCLAS_PMIC_GPIO_BASE (GPIO_BOARD_START + 16) - /* serial port setup */ #define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK) @@ -623,81 +613,16 @@ static struct wm831x_pdata glenfarclas_pmic_pdata __initdata = { .disable_touch = true, }; -static struct wm8996_retune_mobile_config wm8996_retune[] = { - { - .name = "Sub LPF", - .rate = 48000, - .regs = { - 0x6318, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000, - 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000, - 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000 - }, - }, - { - .name = "Sub HPF", - .rate = 48000, - .regs = { - 0x000A, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000, - 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000, - 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000 - }, - }, -}; - -static struct wm8996_pdata wm8996_pdata __initdata = { - .ldo_ena = S3C64XX_GPN(7), - .gpio_base = CODEC_GPIO_BASE, - .micdet_def = 1, - .inl_mode = WM8996_DIFFERRENTIAL_1, - .inr_mode = WM8996_DIFFERRENTIAL_1, - - .irq_flags = IRQF_TRIGGER_RISING, - - .gpio_default = { - 0x8001, /* GPIO1 == ADCLRCLK1 */ - 0x8001, /* GPIO2 == ADCLRCLK2, input due to CPU */ - 0x0141, /* GPIO3 == HP_SEL */ - 0x0002, /* GPIO4 == IRQ */ - 0x020e, /* GPIO5 == CLKOUT */ - }, - - .retune_mobile_cfgs = wm8996_retune, - .num_retune_mobile_cfgs = ARRAY_SIZE(wm8996_retune), -}; - -static struct wm8962_pdata wm8962_pdata __initdata = { - .gpio_init = { - 0, - WM8962_GPIO_FN_OPCLK, - WM8962_GPIO_FN_DMICCLK, - 0, - 0x8000 | WM8962_GPIO_FN_DMICDAT, - WM8962_GPIO_FN_IRQ, /* Open drain mode */ - }, - .irq_active_low = true, -}; - -static struct wm9081_pdata wm9081_pdata __initdata = { - .irq_high = false, - .irq_cmos = false, -}; - static struct i2c_board_info i2c_devs1[] __initdata = { { I2C_BOARD_INFO("wm8311", 0x34), .irq = S3C_EINT(0), .platform_data = &glenfarclas_pmic_pdata }, + { I2C_BOARD_INFO("wlf-gf-module", 0x24) }, + { I2C_BOARD_INFO("wlf-gf-module", 0x25) }, + { I2C_BOARD_INFO("wlf-gf-module", 0x26) }, + { I2C_BOARD_INFO("wm1250-ev1", 0x27) }, - { I2C_BOARD_INFO("wm8996", 0x1a), - .platform_data = &wm8996_pdata, - .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, - }, - { I2C_BOARD_INFO("wm9081", 0x6c), - .platform_data = &wm9081_pdata, }, - { I2C_BOARD_INFO("wm8962", 0x1a), - .platform_data = &wm8962_pdata, - .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, - }, }; static void __init crag6410_map_io(void) From 4ed12b50708875e23ecea191d538e6666b2196eb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 31 Aug 2011 08:03:11 +0900 Subject: [PATCH 0373/1596] ARM: S3C64XX: Hook up some additional supplies on Cragganmore For further modules. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/mach-crag6410.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 1ef53b28f683..9c287a3e28e5 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -285,6 +285,8 @@ static struct platform_device speyside_wm8962_device = { static struct regulator_consumer_supply wallvdd_consumers[] = { REGULATOR_SUPPLY("SPKVDD1", "1-001a"), REGULATOR_SUPPLY("SPKVDD2", "1-001a"), + REGULATOR_SUPPLY("SPKVDDL", "1-001a"), + REGULATOR_SUPPLY("SPKVDDR", "1-001a"), }; static struct regulator_init_data wallvdd_data = { @@ -561,6 +563,9 @@ static struct regulator_init_data pvdd_1v2 __initdata = { static struct regulator_consumer_supply pvdd_1v8_consumers[] __initdata = { REGULATOR_SUPPLY("PLLVDD", "1-001a"), REGULATOR_SUPPLY("DBVDD", "1-001a"), + REGULATOR_SUPPLY("DBVDD1", "1-001a"), + REGULATOR_SUPPLY("DBVDD2", "1-001a"), + REGULATOR_SUPPLY("DBVDD3", "1-001a"), REGULATOR_SUPPLY("CPVDD", "1-001a"), REGULATOR_SUPPLY("AVDD2", "1-001a"), REGULATOR_SUPPLY("DCVDD", "1-001a"), From 3aa7779c748bf340dd122e2d4205f312af977544 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Sep 2011 14:48:39 +0900 Subject: [PATCH 0374/1596] ARM: S3C64XX: Add devices for Kilchoman audio module on Cragganmore The Kilchoman audio module carries a WM5100 audio CODEC and WM9081 speaker amplifier. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/mach-crag6410-module.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c index 0708fa01db9c..66668565ee75 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -89,6 +89,14 @@ static const struct i2c_board_info wm1254_devs[] = { .platform_data = &wm9081_pdata, }, }; +static const struct i2c_board_info wm1255_devs[] = { + { I2C_BOARD_INFO("wm5100", 0x1a), + .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, + }, + { I2C_BOARD_INFO("wm9081", 0x6c), + .platform_data = &wm9081_pdata, }, +}; + static const struct i2c_board_info wm1259_devs[] = { { I2C_BOARD_INFO("wm8962", 0x1a), .platform_data = &wm8962_pdata, @@ -114,7 +122,8 @@ static __devinitdata const struct { .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) }, { .id = 0x3a, .name = "1259-EV1 Tobermory", .i2c_devs = wm1259_devs, .num_i2c_devs = ARRAY_SIZE(wm1259_devs) }, - { .id = 0x3b, .name = "1255-EV1 Kilchoman" }, + { .id = 0x3b, .name = "1255-EV1 Kilchoman", + .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs) }, { .id = 0x3c, .name = "1273-EV1 Longmorn" }, }; From 8c051ab47bf3e0d35636d4772f9c0504bebe2fec Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Sep 2011 14:50:02 +0900 Subject: [PATCH 0375/1596] ARM: S3C64XX: Register Lowland audio device on Cragganmore The Lowland system is a combination of the Cragganmore CPU module and the Tomatin and Kilchomin audio modules on Glenfarclas. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/mach-crag6410.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 9c287a3e28e5..a0422a719996 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -277,6 +277,11 @@ static struct platform_device speyside_device = { .id = -1, }; +static struct platform_device lowland_device = { + .name = "lowland", + .id = -1, +}; + static struct platform_device speyside_wm8962_device = { .name = "speyside-wm8962", .id = -1, @@ -337,6 +342,7 @@ static struct platform_device *crag6410_devices[] __initdata = { &crag6410_backlight_device, &speyside_device, &speyside_wm8962_device, + &lowland_device, &wallvdd_device, }; From 6d8d492ef73433ea8debfba623dc2ee4d627aa7e Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Aug 2011 11:33:08 +0900 Subject: [PATCH 0376/1596] ARM: S3C64XX: Use S3C64XX_SDMA_SEL register name instead of numeric address This patch adds a definition of S3C64XX_SDMA_SEL register and modifies the s3c64xx DMA driver to use it instead of a magic register address. Signed-off-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/dma.c | 2 +- arch/arm/mach-s3c64xx/include/mach/regs-sys.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c index 204bfafe4bfc..0849f2d3b105 100644 --- a/arch/arm/mach-s3c64xx/dma.c +++ b/arch/arm/mach-s3c64xx/dma.c @@ -740,7 +740,7 @@ static int __init s3c64xx_dma_init(void) } /* Set all DMA configuration to be DMA, not SDMA */ - writel(0xffffff, S3C_SYSREG(0x110)); + writel(0xffffff, S3C64XX_SDMA_SEL); /* Register standard DMA controllers */ s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000); diff --git a/arch/arm/mach-s3c64xx/include/mach/regs-sys.h b/arch/arm/mach-s3c64xx/include/mach/regs-sys.h index 69b78d9f83b8..774e0de31400 100644 --- a/arch/arm/mach-s3c64xx/include/mach/regs-sys.h +++ b/arch/arm/mach-s3c64xx/include/mach/regs-sys.h @@ -21,6 +21,8 @@ #define S3C64XX_AHB_CON1 S3C_SYSREG(0x104) #define S3C64XX_AHB_CON2 S3C_SYSREG(0x108) +#define S3C64XX_SDMA_SEL S3C_SYSREG(0x110) + #define S3C64XX_OTHERS S3C_SYSREG(0x900) #define S3C64XX_OTHERS_USBMASK (1 << 16) From 348276f4a37ab98559c8c63cbe2a122b7ff65421 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Aug 2011 11:33:08 +0900 Subject: [PATCH 0377/1596] ARM: S3C64XX: Save/restore S3C64XX_SDMA_SEL on suspend/resume This patch makes sure that S3C64XX_SDMA_SEL register is preserved during sleep mode, as it is critical for DMA operation and the DMA driver alone does not provide any power management facilities. Signed-off-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/pm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index 055e2858b0dd..72e3ab2ac088 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -85,6 +85,8 @@ static struct sleep_save misc_save[] = { SAVE_ITEM(S3C64XX_MEM0CONSLP0), SAVE_ITEM(S3C64XX_MEM0CONSLP1), SAVE_ITEM(S3C64XX_MEM1CONSLP), + + SAVE_ITEM(S3C64XX_SDMA_SEL), }; void s3c_pm_configure_extint(void) From d9018df00785d7ff52aa7fa8acfacd8a036fc832 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 23 Aug 2011 11:33:08 +0900 Subject: [PATCH 0378/1596] ARM: S3C64XX: Save/restore S3C64XX_MODEM_MIFPCON on suspend/resume This patch makes sure that the LCD bypass state is preserved during sleep mode. It achieves this by saving the S3C64XX_MODEM_MIFPCON register, which is not handled by any other code currently. Signed-off-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/pm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index 72e3ab2ac088..b375cd5c47cb 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK void s3c_pm_debug_smdkled(u32 set, u32 clear) @@ -87,6 +88,7 @@ static struct sleep_save misc_save[] = { SAVE_ITEM(S3C64XX_MEM1CONSLP), SAVE_ITEM(S3C64XX_SDMA_SEL), + SAVE_ITEM(S3C64XX_MODEM_MIFPCON), }; void s3c_pm_configure_extint(void) From fb5d375d352ee5830b33ccdff06eb4f5f1d603f5 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Fri, 19 Aug 2011 11:54:31 +0200 Subject: [PATCH 0379/1596] ARM: S3C64XX: Add support for synchronous clock operation Some boards based on S3C6410 use synchronous clocking, which means that HCLKx2 and other system clocks are generated from APLL instead of MPLL. This patch adds support for such boards, by calculating hclk2 depending on the status of S3C_OTHERS_SYNCMUXSEL bit in S3C64XX_OTHERS regist Signed-off-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/clock.c | 8 +++++++- arch/arm/mach-s3c64xx/include/mach/regs-sys.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c index 8cf39e33579e..872e68361eb4 100644 --- a/arch/arm/mach-s3c64xx/clock.c +++ b/arch/arm/mach-s3c64xx/clock.c @@ -744,7 +744,13 @@ void __init_or_cpufreq s3c6400_setup_clocks(void) printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n", apll, mpll, epll); - hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2); + if(__raw_readl(S3C64XX_OTHERS) & S3C64XX_OTHERS_SYNCMUXSEL) + /* Synchronous mode */ + hclk2 = apll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2); + else + /* Asynchronous mode */ + hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2); + hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK); pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK); diff --git a/arch/arm/mach-s3c64xx/include/mach/regs-sys.h b/arch/arm/mach-s3c64xx/include/mach/regs-sys.h index 774e0de31400..b91e02093289 100644 --- a/arch/arm/mach-s3c64xx/include/mach/regs-sys.h +++ b/arch/arm/mach-s3c64xx/include/mach/regs-sys.h @@ -26,5 +26,6 @@ #define S3C64XX_OTHERS S3C_SYSREG(0x900) #define S3C64XX_OTHERS_USBMASK (1 << 16) +#define S3C64XX_OTHERS_SYNCMUXSEL (1 << 6) #endif /* _PLAT_REGS_SYS_H */ From b7f69d9d4283cfbbf7458962cf9bdba6463b831d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:43 +0530 Subject: [PATCH 0380/1596] dmaengine/amba-pl08x: Add support for sg len greater than one for slave transfers Untill now, sg_len greater than one is not supported. This patch adds support to do that. Note: Still, if peripheral is flow controller, sg_len can't be greater that one. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 378 +++++++++++++++++++++---------------- include/linux/amba/pl08x.h | 22 ++- 2 files changed, 231 insertions(+), 169 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index cd8df7f5b5c8..2c390d1b9cad 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -352,7 +352,9 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *txdi; list_for_each_entry(txdi, &plchan->pend_list, node) { - bytes += txdi->len; + struct pl08x_sg *dsg; + list_for_each_entry(dsg, &txd->dsg_list, node) + bytes += dsg->len; } } @@ -567,8 +569,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_lli_build_data bd; int num_llis = 0; u32 cctl, early_bytes = 0; - size_t max_bytes_per_lli, total_bytes = 0; + size_t max_bytes_per_lli, total_bytes; struct pl08x_lli *llis_va; + struct pl08x_sg *dsg; txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus); if (!txd->llis_va) { @@ -578,13 +581,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x->pool_ctr++; - /* Get the default CCTL */ - cctl = txd->cctl; - bd.txd = txd; - bd.srcbus.addr = txd->src_addr; - bd.dstbus.addr = txd->dst_addr; bd.lli_bus = (pl08x->lli_buses & PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0; + cctl = txd->cctl; /* Find maximum width of the source bus */ bd.srcbus.maxwidth = @@ -596,162 +595,179 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >> PL080_CONTROL_DWIDTH_SHIFT); - /* Set up the bus widths to the maximum */ - bd.srcbus.buswidth = bd.srcbus.maxwidth; - bd.dstbus.buswidth = bd.dstbus.maxwidth; + list_for_each_entry(dsg, &txd->dsg_list, node) { + total_bytes = 0; + cctl = txd->cctl; - /* We need to count this down to zero */ - bd.remainder = txd->len; + bd.srcbus.addr = dsg->src_addr; + bd.dstbus.addr = dsg->dst_addr; + bd.remainder = dsg->len; + bd.srcbus.buswidth = bd.srcbus.maxwidth; + bd.dstbus.buswidth = bd.dstbus.maxwidth; - pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); + pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); - dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu\n", - bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "", - bd.srcbus.buswidth, - bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "", - bd.dstbus.buswidth, - bd.remainder); - dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n", - mbus == &bd.srcbus ? "src" : "dst", - sbus == &bd.srcbus ? "src" : "dst"); + dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu\n", + bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "", + bd.srcbus.buswidth, + bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "", + bd.dstbus.buswidth, + bd.remainder); + dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n", + mbus == &bd.srcbus ? "src" : "dst", + sbus == &bd.srcbus ? "src" : "dst"); - /* - * Zero length is only allowed if all these requirements are met: - * - flow controller is peripheral. - * - src.addr is aligned to src.width - * - dst.addr is aligned to dst.width - * - * sg_len == 1 should be true, as there can be two cases here: - * - Memory addresses are contiguous and are not scattered. Here, Only - * one sg will be passed by user driver, with memory address and zero - * length. We pass this to controller and after the transfer it will - * receive the last burst request from peripheral and so transfer - * finishes. - * - * - Memory addresses are scattered and are not contiguous. Here, - * Obviously as DMA controller doesn't know when a lli's transfer gets - * over, it can't load next lli. So in this case, there has to be an - * assumption that only one lli is supported. Thus, we can't have - * scattered addresses. - */ - if (!bd.remainder) { - u32 fc = (txd->ccfg & PL080_CONFIG_FLOW_CONTROL_MASK) >> - PL080_CONFIG_FLOW_CONTROL_SHIFT; - if (!((fc >= PL080_FLOW_SRC2DST_DST) && + /* + * Zero length is only allowed if all these requirements are + * met: + * - flow controller is peripheral. + * - src.addr is aligned to src.width + * - dst.addr is aligned to dst.width + * + * sg_len == 1 should be true, as there can be two cases here: + * + * - Memory addresses are contiguous and are not scattered. + * Here, Only one sg will be passed by user driver, with + * memory address and zero length. We pass this to controller + * and after the transfer it will receive the last burst + * request from peripheral and so transfer finishes. + * + * - Memory addresses are scattered and are not contiguous. + * Here, Obviously as DMA controller doesn't know when a lli's + * transfer gets over, it can't load next lli. So in this + * case, there has to be an assumption that only one lli is + * supported. Thus, we can't have scattered addresses. + */ + if (!bd.remainder) { + u32 fc = (txd->ccfg & PL080_CONFIG_FLOW_CONTROL_MASK) >> + PL080_CONFIG_FLOW_CONTROL_SHIFT; + if (!((fc >= PL080_FLOW_SRC2DST_DST) && (fc <= PL080_FLOW_SRC2DST_SRC))) { - dev_err(&pl08x->adev->dev, "%s sg len can't be zero", - __func__); - return 0; - } - - if ((bd.srcbus.addr % bd.srcbus.buswidth) || - (bd.srcbus.addr % bd.srcbus.buswidth)) { - dev_err(&pl08x->adev->dev, - "%s src & dst address must be aligned to src" - " & dst width if peripheral is flow controller", - __func__); - return 0; - } - - cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, - bd.dstbus.buswidth, 0); - pl08x_fill_lli_for_desc(&bd, num_llis++, 0, cctl); - } + dev_err(&pl08x->adev->dev, "%s sg len can't be zero", + __func__); + return 0; + } - /* - * Send byte by byte for following cases - * - Less than a bus width available - * - until master bus is aligned - */ - if (bd.remainder < mbus->buswidth) - early_bytes = bd.remainder; - else if ((mbus->addr) % (mbus->buswidth)) { - early_bytes = mbus->buswidth - (mbus->addr) % (mbus->buswidth); - if ((bd.remainder - early_bytes) < mbus->buswidth) - early_bytes = bd.remainder; - } + if ((bd.srcbus.addr % bd.srcbus.buswidth) || + (bd.srcbus.addr % bd.srcbus.buswidth)) { + dev_err(&pl08x->adev->dev, + "%s src & dst address must be aligned to src" + " & dst width if peripheral is flow controller", + __func__); + return 0; + } - if (early_bytes) { - dev_vdbg(&pl08x->adev->dev, "%s byte width LLIs " - "(remain 0x%08x)\n", __func__, bd.remainder); - prep_byte_width_lli(&bd, &cctl, early_bytes, num_llis++, - &total_bytes); - } + cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, + bd.dstbus.buswidth, 0); + pl08x_fill_lli_for_desc(&bd, num_llis++, 0, cctl); + break; + } - if (bd.remainder) { /* - * Master now aligned - * - if slave is not then we must set its width down + * Send byte by byte for following cases + * - Less than a bus width available + * - until master bus is aligned */ - if (sbus->addr % sbus->buswidth) { - dev_dbg(&pl08x->adev->dev, - "%s set down bus width to one byte\n", - __func__); + if (bd.remainder < mbus->buswidth) + early_bytes = bd.remainder; + else if ((mbus->addr) % (mbus->buswidth)) { + early_bytes = mbus->buswidth - (mbus->addr) % + (mbus->buswidth); + if ((bd.remainder - early_bytes) < mbus->buswidth) + early_bytes = bd.remainder; + } - sbus->buswidth = 1; + if (early_bytes) { + dev_vdbg(&pl08x->adev->dev, + "%s byte width LLIs (remain 0x%08x)\n", + __func__, bd.remainder); + prep_byte_width_lli(&bd, &cctl, early_bytes, num_llis++, + &total_bytes); } - /* Bytes transferred = tsize * src width, not MIN(buswidths) */ - max_bytes_per_lli = bd.srcbus.buswidth * - PL080_CONTROL_TRANSFER_SIZE_MASK; + if (bd.remainder) { + /* + * Master now aligned + * - if slave is not then we must set its width down + */ + if (sbus->addr % sbus->buswidth) { + dev_dbg(&pl08x->adev->dev, + "%s set down bus width to one byte\n", + __func__); - /* - * Make largest possible LLIs until less than one bus - * width left - */ - while (bd.remainder > (mbus->buswidth - 1)) { - size_t lli_len, tsize, width; + sbus->buswidth = 1; + } /* - * If enough left try to send max possible, - * otherwise try to send the remainder + * Bytes transferred = tsize * src width, not + * MIN(buswidths) */ - lli_len = min(bd.remainder, max_bytes_per_lli); + max_bytes_per_lli = bd.srcbus.buswidth * + PL080_CONTROL_TRANSFER_SIZE_MASK; + dev_vdbg(&pl08x->adev->dev, + "%s max bytes per lli = %zu\n", + __func__, max_bytes_per_lli); /* - * Check against maximum bus alignment: Calculate actual - * transfer size in relation to bus width and get a - * maximum remainder of the highest bus width - 1 + * Make largest possible LLIs until less than one bus + * width left */ - width = max(mbus->buswidth, sbus->buswidth); - lli_len = (lli_len / width) * width; - tsize = lli_len / bd.srcbus.buswidth; + while (bd.remainder > (mbus->buswidth - 1)) { + size_t lli_len, tsize, width; - dev_vdbg(&pl08x->adev->dev, - "%s fill lli with single lli chunk of " - "size 0x%08zx (remainder 0x%08zx)\n", - __func__, lli_len, bd.remainder); + /* + * If enough left try to send max possible, + * otherwise try to send the remainder + */ + lli_len = min(bd.remainder, max_bytes_per_lli); - cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, + /* + * Check against maximum bus alignment: + * Calculate actual transfer size in relation to + * bus width an get a maximum remainder of the + * highest bus width - 1 + */ + width = max(mbus->buswidth, sbus->buswidth); + lli_len = (lli_len / width) * width; + tsize = lli_len / bd.srcbus.buswidth; + + dev_vdbg(&pl08x->adev->dev, + "%s fill lli with single lli chunk of " + "size 0x%08zx (remainder 0x%08zx)\n", + __func__, lli_len, bd.remainder); + + cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, bd.dstbus.buswidth, tsize); - pl08x_fill_lli_for_desc(&bd, num_llis++, lli_len, cctl); - total_bytes += lli_len; - } + pl08x_fill_lli_for_desc(&bd, num_llis++, + lli_len, cctl); + total_bytes += lli_len; + } - /* - * Send any odd bytes - */ - if (bd.remainder) { - dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, send odd bytes (remain %zu)\n", - __func__, bd.remainder); - prep_byte_width_lli(&bd, &cctl, bd.remainder, - num_llis++, &total_bytes); + /* + * Send any odd bytes + */ + if (bd.remainder) { + dev_vdbg(&pl08x->adev->dev, + "%s align with boundary, send odd bytes (remain %zu)\n", + __func__, bd.remainder); + prep_byte_width_lli(&bd, &cctl, bd.remainder, + num_llis++, &total_bytes); + } } - } - if (total_bytes != txd->len) { - dev_err(&pl08x->adev->dev, - "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n", - __func__, total_bytes, txd->len); - return 0; - } + if (total_bytes != dsg->len) { + dev_err(&pl08x->adev->dev, + "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n", + __func__, total_bytes, dsg->len); + return 0; + } - if (num_llis >= MAX_NUM_TSFR_LLIS) { - dev_err(&pl08x->adev->dev, - "%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n", - __func__, (u32) MAX_NUM_TSFR_LLIS); - return 0; + if (num_llis >= MAX_NUM_TSFR_LLIS) { + dev_err(&pl08x->adev->dev, + "%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n", + __func__, (u32) MAX_NUM_TSFR_LLIS); + return 0; + } } llis_va = txd->llis_va; @@ -784,11 +800,18 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, static void pl08x_free_txd(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { + struct pl08x_sg *dsg, *_dsg; + /* Free the LLI */ dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus); pl08x->pool_ctr--; + list_for_each_entry_safe(dsg, _dsg, &txd->dsg_list, node) { + list_del(&dsg->node); + kfree(dsg); + } + kfree(txd); } @@ -1234,6 +1257,7 @@ static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, txd->tx.flags = flags; txd->tx.tx_submit = pl08x_tx_submit; INIT_LIST_HEAD(&txd->node); + INIT_LIST_HEAD(&txd->dsg_list); /* Always enable error and terminal interrupts */ txd->ccfg = PL080_CONFIG_ERR_IRQ_MASK | @@ -1252,6 +1276,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; + struct pl08x_sg *dsg; int ret; txd = pl08x_get_txd(plchan, flags); @@ -1261,10 +1286,19 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( return NULL; } + dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT); + if (!dsg) { + pl08x_free_txd(pl08x, txd); + dev_err(&pl08x->adev->dev, "%s no memory for pl080 sg\n", + __func__); + return NULL; + } + list_add_tail(&dsg->node, &txd->dsg_list); + txd->direction = DMA_NONE; - txd->src_addr = src; - txd->dst_addr = dest; - txd->len = len; + dsg->src_addr = src; + dsg->dst_addr = dest; + dsg->len = len; /* Set platform data for m2m */ txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; @@ -1293,19 +1327,13 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; + struct pl08x_sg *dsg; + struct scatterlist *sg; + dma_addr_t slave_addr; int ret, tmp; - /* - * Current implementation ASSUMES only one sg - */ - if (sg_len != 1) { - dev_err(&pl08x->adev->dev, "%s prepared too long sglist\n", - __func__); - BUG(); - } - dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n", - __func__, sgl->length, plchan->name); + __func__, sgl->length, plchan->name); txd = pl08x_get_txd(plchan, flags); if (!txd) { @@ -1324,17 +1352,15 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( * channel target address dynamically at runtime. */ txd->direction = direction; - txd->len = sgl->length; if (direction == DMA_TO_DEVICE) { txd->cctl = plchan->dst_cctl; - txd->src_addr = sgl->dma_address; - txd->dst_addr = plchan->dst_addr; + slave_addr = plchan->dst_addr; } else if (direction == DMA_FROM_DEVICE) { txd->cctl = plchan->src_cctl; - txd->src_addr = plchan->src_addr; - txd->dst_addr = sgl->dma_address; + slave_addr = plchan->src_addr; } else { + pl08x_free_txd(pl08x, txd); dev_err(&pl08x->adev->dev, "%s direction unsupported\n", __func__); return NULL; @@ -1349,6 +1375,26 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( txd->ccfg |= tmp << PL080_CONFIG_FLOW_CONTROL_SHIFT; + for_each_sg(sgl, sg, sg_len, tmp) { + dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT); + if (!dsg) { + pl08x_free_txd(pl08x, txd); + dev_err(&pl08x->adev->dev, "%s no mem for pl080 sg\n", + __func__); + return NULL; + } + list_add_tail(&dsg->node, &txd->dsg_list); + + dsg->len = sg_dma_len(sg); + if (direction == DMA_TO_DEVICE) { + dsg->src_addr = sg_phys(sg); + dsg->dst_addr = slave_addr; + } else { + dsg->src_addr = slave_addr; + dsg->dst_addr = sg_phys(sg); + } + } + ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; @@ -1452,22 +1498,28 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) static void pl08x_unmap_buffers(struct pl08x_txd *txd) { struct device *dev = txd->tx.chan->device->dev; + struct pl08x_sg *dsg; if (!(txd->tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) { if (txd->tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE) - dma_unmap_single(dev, txd->src_addr, txd->len, - DMA_TO_DEVICE); - else - dma_unmap_page(dev, txd->src_addr, txd->len, - DMA_TO_DEVICE); + list_for_each_entry(dsg, &txd->dsg_list, node) + dma_unmap_single(dev, dsg->src_addr, dsg->len, + DMA_TO_DEVICE); + else { + list_for_each_entry(dsg, &txd->dsg_list, node) + dma_unmap_page(dev, dsg->src_addr, dsg->len, + DMA_TO_DEVICE); + } } if (!(txd->tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) { if (txd->tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE) - dma_unmap_single(dev, txd->dst_addr, txd->len, - DMA_FROM_DEVICE); + list_for_each_entry(dsg, &txd->dsg_list, node) + dma_unmap_single(dev, dsg->dst_addr, dsg->len, + DMA_FROM_DEVICE); else - dma_unmap_page(dev, txd->dst_addr, txd->len, - DMA_FROM_DEVICE); + list_for_each_entry(dsg, &txd->dsg_list, node) + dma_unmap_page(dev, dsg->dst_addr, dsg->len, + DMA_FROM_DEVICE); } } diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index a22662c93981..9eabffbc4e50 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -105,13 +105,25 @@ struct pl08x_phy_chan { struct pl08x_dma_chan *serving; }; +/** + * struct pl08x_sg - structure containing data per sg + * @src_addr: src address of sg + * @dst_addr: dst address of sg + * @len: transfer len in bytes + * @node: node for txd's dsg_list + */ +struct pl08x_sg { + dma_addr_t src_addr; + dma_addr_t dst_addr; + size_t len; + struct list_head node; +}; + /** * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor * @tx: async tx descriptor * @node: node for txd list for channels - * @src_addr: src address of txd - * @dst_addr: dst address of txd - * @len: transfer len in bytes + * @dsg_list: list of children sg's * @direction: direction of transfer * @llis_bus: DMA memory address (physical) start for the LLIs * @llis_va: virtual memory address start for the LLIs @@ -121,10 +133,8 @@ struct pl08x_phy_chan { struct pl08x_txd { struct dma_async_tx_descriptor tx; struct list_head node; + struct list_head dsg_list; enum dma_data_direction direction; - dma_addr_t src_addr; - dma_addr_t dst_addr; - size_t len; dma_addr_t llis_bus; struct pl08x_lli *llis_va; /* Default cctl value for LLIs */ From c12056466d76cdff884402d15f077dd0586e5215 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 5 Aug 2011 15:32:44 +0530 Subject: [PATCH 0381/1596] dmaengine/amba-pl08x: Check txd->llis_va before freeing dma_pool In pl08x_free_txd(), check if pool is allocated successfully before freeing it. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 2c390d1b9cad..b7cbd1ab1db1 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -803,7 +803,8 @@ static void pl08x_free_txd(struct pl08x_driver_data *pl08x, struct pl08x_sg *dsg, *_dsg; /* Free the LLI */ - dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus); + if (txd->llis_va) + dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus); pl08x->pool_ctr--; From 3a8f7558e475b68254d8bc3a2211f3f89bf67a71 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Fri, 24 Jun 2011 09:05:23 +0000 Subject: [PATCH 0382/1596] dma-mapping: Add get_required_mask if arch overrides default If an architecture sets ARCH_HAS_DMA_GET_REQUIRED_MASK and has settable dma_map_ops, the required mask may change by the ops implementation. For example, a system that always has an mmu inline may only require 32 bits while a swiotlb would desire bits to cover all of memory. Therefore add the field if the architecture does not use the generic definition of dma_get_required_mask. The first use will by by powerpc. Note that this does add some dependency on the order in which files are visible here. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt Acked-by: FUJITA Tomonori --- include/linux/dma-mapping.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 347fdc32177a..aa32fecd1d34 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -41,6 +41,9 @@ struct dma_map_ops { int (*mapping_error)(struct device *dev, dma_addr_t dma_addr); int (*dma_supported)(struct device *dev, u64 mask); int (*set_dma_mask)(struct device *dev, u64 mask); +#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK + u64 (*get_required_mask)(struct device *dev); +#endif int is_phys; }; From d24f9c6999eacd3a7bc2b289e49fcb2bf2fafef2 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Fri, 24 Jun 2011 09:05:24 +0000 Subject: [PATCH 0383/1596] powerpc: Use the newly added get_required_mask dma_map_ops hook Now that the generic code has dma_map_ops set, instead of having a messy ifdef & if block in the base dma_get_required_mask hook push the computation into the dma ops. If the ops fails to set the get_required_mask hook default to the width of dma_addr_t. This also corrects ibmbus ibmebus_dma_supported to require a 64 bit mask. I doubt anything is checking or setting the dma mask on that bus. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org Cc: benh@kernel.crashing.org Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/device.h | 2 ++ arch/powerpc/include/asm/dma-mapping.h | 3 -- arch/powerpc/kernel/dma-iommu.c | 3 +- arch/powerpc/kernel/dma-swiotlb.c | 16 ++++++++++ arch/powerpc/kernel/dma.c | 41 ++++++++++--------------- arch/powerpc/kernel/ibmebus.c | 8 ++++- arch/powerpc/kernel/vio.c | 7 ++++- arch/powerpc/platforms/cell/iommu.c | 13 ++++++-- arch/powerpc/platforms/ps3/system-bus.c | 7 +++++ arch/powerpc/platforms/pseries/iommu.c | 2 +- 10 files changed, 68 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index 16d25c0974be..d57c08acedfc 100644 --- a/arch/powerpc/include/asm/device.h +++ b/arch/powerpc/include/asm/device.h @@ -37,4 +37,6 @@ struct pdev_archdata { u64 dma_mask; }; +#define ARCH_HAS_DMA_GET_REQUIRED_MASK + #endif /* _ASM_POWERPC_DEVICE_H */ diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index 8135e66a4bb9..dd70fac57ec8 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -20,8 +20,6 @@ #define DMA_ERROR_CODE (~(dma_addr_t)0x0) -#define ARCH_HAS_DMA_GET_REQUIRED_MASK - /* Some dma direct funcs must be visible for use in other dma_ops */ extern void *dma_direct_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag); @@ -71,7 +69,6 @@ static inline unsigned long device_to_mask(struct device *dev) */ #ifdef CONFIG_PPC64 extern struct dma_map_ops dma_iommu_ops; -extern u64 dma_iommu_get_required_mask(struct device *dev); #endif extern struct dma_map_ops dma_direct_ops; diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index 1f2a711a261e..c1ad9db934f6 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -90,7 +90,7 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask) return 1; } -u64 dma_iommu_get_required_mask(struct device *dev) +static u64 dma_iommu_get_required_mask(struct device *dev) { struct iommu_table *tbl = get_iommu_table_base(dev); u64 mask; @@ -111,5 +111,6 @@ struct dma_map_ops dma_iommu_ops = { .dma_supported = dma_iommu_dma_supported, .map_page = dma_iommu_map_page, .unmap_page = dma_iommu_unmap_page, + .get_required_mask = dma_iommu_get_required_mask, }; EXPORT_SYMBOL(dma_iommu_ops); diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index 4295e0b94b2d..1ebc9189aada 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c @@ -24,6 +24,21 @@ unsigned int ppc_swiotlb_enable; +static u64 swiotlb_powerpc_get_required(struct device *dev) +{ + u64 end, mask, max_direct_dma_addr = dev->archdata.max_direct_dma_addr; + + end = memblock_end_of_DRAM(); + if (max_direct_dma_addr && end > max_direct_dma_addr) + end = max_direct_dma_addr; + end += get_dma_offset(dev); + + mask = 1ULL << (fls64(end) - 1); + mask += mask - 1; + + return mask; +} + /* * At the moment, all platforms that use this code only require * swiotlb to be used if we're operating on HIGHMEM. Since @@ -44,6 +59,7 @@ struct dma_map_ops swiotlb_dma_ops = { .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, .sync_sg_for_device = swiotlb_sync_sg_for_device, .mapping_error = swiotlb_dma_mapping_error, + .get_required_mask = swiotlb_powerpc_get_required, }; void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev) diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 503093efa202..10b136afbf50 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -96,6 +96,18 @@ static int dma_direct_dma_supported(struct device *dev, u64 mask) #endif } +static u64 dma_direct_get_required_mask(struct device *dev) +{ + u64 end, mask; + + end = memblock_end_of_DRAM() + get_dma_offset(dev); + + mask = 1ULL << (fls64(end) - 1); + mask += mask - 1; + + return mask; +} + static inline dma_addr_t dma_direct_map_page(struct device *dev, struct page *page, unsigned long offset, @@ -144,6 +156,7 @@ struct dma_map_ops dma_direct_ops = { .dma_supported = dma_direct_dma_supported, .map_page = dma_direct_map_page, .unmap_page = dma_direct_unmap_page, + .get_required_mask = dma_direct_get_required_mask, #ifdef CONFIG_NOT_COHERENT_CACHE .sync_single_for_cpu = dma_direct_sync_single, .sync_single_for_device = dma_direct_sync_single, @@ -173,7 +186,6 @@ EXPORT_SYMBOL(dma_set_mask); u64 dma_get_required_mask(struct device *dev) { struct dma_map_ops *dma_ops = get_dma_ops(dev); - u64 mask, end = 0; if (ppc_md.dma_get_required_mask) return ppc_md.dma_get_required_mask(dev); @@ -181,31 +193,10 @@ u64 dma_get_required_mask(struct device *dev) if (unlikely(dma_ops == NULL)) return 0; -#ifdef CONFIG_PPC64 - else if (dma_ops == &dma_iommu_ops) - return dma_iommu_get_required_mask(dev); -#endif -#ifdef CONFIG_SWIOTLB - else if (dma_ops == &swiotlb_dma_ops) { - u64 max_direct_dma_addr = dev->archdata.max_direct_dma_addr; - - end = memblock_end_of_DRAM(); - if (max_direct_dma_addr && end > max_direct_dma_addr) - end = max_direct_dma_addr; - end += get_dma_offset(dev); - } -#endif - else if (dma_ops == &dma_direct_ops) - end = memblock_end_of_DRAM() + get_dma_offset(dev); - else { - WARN_ONCE(1, "%s: unknown ops %p\n", __func__, dma_ops); - end = memblock_end_of_DRAM(); - } + if (dma_ops->get_required_mask) + return dma_ops->get_required_mask(dev); - mask = 1ULL << (fls64(end) - 1); - mask += mask - 1; - - return mask; + return DMA_BIT_MASK(8 * sizeof(dma_addr_t)); } EXPORT_SYMBOL_GPL(dma_get_required_mask); diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 28581f1ad2c0..90ef2a44613b 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -125,7 +125,12 @@ static void ibmebus_unmap_sg(struct device *dev, static int ibmebus_dma_supported(struct device *dev, u64 mask) { - return 1; + return mask == DMA_BIT_MASK(64); +} + +static u64 ibmebus_dma_get_required_mask(struct device *dev) +{ + return DMA_BIT_MASK(64); } static struct dma_map_ops ibmebus_dma_ops = { @@ -134,6 +139,7 @@ static struct dma_map_ops ibmebus_dma_ops = { .map_sg = ibmebus_map_sg, .unmap_sg = ibmebus_unmap_sg, .dma_supported = ibmebus_dma_supported, + .get_required_mask = ibmebus_dma_get_required_mask, .map_page = ibmebus_map_page, .unmap_page = ibmebus_unmap_page, }; diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 1b695fdc362b..c0493259d133 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -605,6 +605,11 @@ static int vio_dma_iommu_dma_supported(struct device *dev, u64 mask) return dma_iommu_ops.dma_supported(dev, mask); } +static u64 vio_dma_get_required_mask(struct device *dev) +{ + return dma_iommu_ops.get_required_mask(dev); +} + struct dma_map_ops vio_dma_mapping_ops = { .alloc_coherent = vio_dma_iommu_alloc_coherent, .free_coherent = vio_dma_iommu_free_coherent, @@ -613,7 +618,7 @@ struct dma_map_ops vio_dma_mapping_ops = { .map_page = vio_dma_iommu_map_page, .unmap_page = vio_dma_iommu_unmap_page, .dma_supported = vio_dma_iommu_dma_supported, - + .get_required_mask = vio_dma_get_required_mask, }; /** diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 5ef55f3b0987..fc46fcac3921 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -1161,11 +1161,20 @@ __setup("iommu_fixed=", setup_iommu_fixed); static u64 cell_dma_get_required_mask(struct device *dev) { + struct dma_map_ops *dma_ops; + if (!dev->dma_mask) return 0; - if (iommu_fixed_disabled && get_dma_ops(dev) == &dma_iommu_ops) - return dma_iommu_get_required_mask(dev); + if (!iommu_fixed_disabled && + cell_iommu_get_fixed_address(dev) != OF_BAD_ADDR) + return DMA_BIT_MASK(64); + + dma_ops = get_dma_ops(dev); + if (dma_ops->get_required_mask) + return dma_ops->get_required_mask(dev); + + WARN_ONCE(1, "no get_required_mask in %p ops", dma_ops); return DMA_BIT_MASK(64); } diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 23083c397528..688141c76e03 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -695,12 +695,18 @@ static int ps3_dma_supported(struct device *_dev, u64 mask) return mask >= DMA_BIT_MASK(32); } +static u64 ps3_dma_get_required_mask(struct device *_dev) +{ + return DMA_BIT_MASK(32); +} + static struct dma_map_ops ps3_sb_dma_ops = { .alloc_coherent = ps3_alloc_coherent, .free_coherent = ps3_free_coherent, .map_sg = ps3_sb_map_sg, .unmap_sg = ps3_sb_unmap_sg, .dma_supported = ps3_dma_supported, + .get_required_mask = ps3_dma_get_required_mask, .map_page = ps3_sb_map_page, .unmap_page = ps3_unmap_page, }; @@ -711,6 +717,7 @@ static struct dma_map_ops ps3_ioc0_dma_ops = { .map_sg = ps3_ioc0_map_sg, .unmap_sg = ps3_ioc0_unmap_sg, .dma_supported = ps3_dma_supported, + .get_required_mask = ps3_dma_get_required_mask, .map_page = ps3_ioc0_map_page, .unmap_page = ps3_unmap_page, }; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index fe5ededf0d60..9f121a37eb51 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -1099,7 +1099,7 @@ static u64 dma_get_required_mask_pSeriesLP(struct device *dev) return DMA_BIT_MASK(64); } - return dma_iommu_get_required_mask(dev); + return dma_iommu_ops.get_required_mask(dev); } #else /* CONFIG_PCI */ From 2eccacd0974dca73e2151d3fd4c2dacf1a5c7cc2 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Fri, 24 Jun 2011 09:05:25 +0000 Subject: [PATCH 0384/1596] powerpc: Tidy up dma_map_ops after adding new hook The new get_required_mask hook name is longer than many of but not all of the prior ops. Tidy the struct initializers to align the equal signs using the local whitespace. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org Cc: benh@kernel.crashing.org Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/dma-iommu.c | 14 +++++++------- arch/powerpc/kernel/dma.c | 16 ++++++++-------- arch/powerpc/kernel/ibmebus.c | 14 +++++++------- arch/powerpc/kernel/vio.c | 14 +++++++------- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index c1ad9db934f6..6f04b9c383a7 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -104,13 +104,13 @@ static u64 dma_iommu_get_required_mask(struct device *dev) } struct dma_map_ops dma_iommu_ops = { - .alloc_coherent = dma_iommu_alloc_coherent, - .free_coherent = dma_iommu_free_coherent, - .map_sg = dma_iommu_map_sg, - .unmap_sg = dma_iommu_unmap_sg, - .dma_supported = dma_iommu_dma_supported, - .map_page = dma_iommu_map_page, - .unmap_page = dma_iommu_unmap_page, + .alloc_coherent = dma_iommu_alloc_coherent, + .free_coherent = dma_iommu_free_coherent, + .map_sg = dma_iommu_map_sg, + .unmap_sg = dma_iommu_unmap_sg, + .dma_supported = dma_iommu_dma_supported, + .map_page = dma_iommu_map_page, + .unmap_page = dma_iommu_unmap_page, .get_required_mask = dma_iommu_get_required_mask, }; EXPORT_SYMBOL(dma_iommu_ops); diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 10b136afbf50..8593f53c4f6c 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -149,14 +149,14 @@ static inline void dma_direct_sync_single(struct device *dev, #endif struct dma_map_ops dma_direct_ops = { - .alloc_coherent = dma_direct_alloc_coherent, - .free_coherent = dma_direct_free_coherent, - .map_sg = dma_direct_map_sg, - .unmap_sg = dma_direct_unmap_sg, - .dma_supported = dma_direct_dma_supported, - .map_page = dma_direct_map_page, - .unmap_page = dma_direct_unmap_page, - .get_required_mask = dma_direct_get_required_mask, + .alloc_coherent = dma_direct_alloc_coherent, + .free_coherent = dma_direct_free_coherent, + .map_sg = dma_direct_map_sg, + .unmap_sg = dma_direct_unmap_sg, + .dma_supported = dma_direct_dma_supported, + .map_page = dma_direct_map_page, + .unmap_page = dma_direct_unmap_page, + .get_required_mask = dma_direct_get_required_mask, #ifdef CONFIG_NOT_COHERENT_CACHE .sync_single_for_cpu = dma_direct_sync_single, .sync_single_for_device = dma_direct_sync_single, diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 90ef2a44613b..73110fb6bb6c 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -134,14 +134,14 @@ static u64 ibmebus_dma_get_required_mask(struct device *dev) } static struct dma_map_ops ibmebus_dma_ops = { - .alloc_coherent = ibmebus_alloc_coherent, - .free_coherent = ibmebus_free_coherent, - .map_sg = ibmebus_map_sg, - .unmap_sg = ibmebus_unmap_sg, - .dma_supported = ibmebus_dma_supported, + .alloc_coherent = ibmebus_alloc_coherent, + .free_coherent = ibmebus_free_coherent, + .map_sg = ibmebus_map_sg, + .unmap_sg = ibmebus_unmap_sg, + .dma_supported = ibmebus_dma_supported, .get_required_mask = ibmebus_dma_get_required_mask, - .map_page = ibmebus_map_page, - .unmap_page = ibmebus_unmap_page, + .map_page = ibmebus_map_page, + .unmap_page = ibmebus_unmap_page, }; static int ibmebus_match_path(struct device *dev, void *data) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index c0493259d133..34d291d83ec8 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -611,13 +611,13 @@ static u64 vio_dma_get_required_mask(struct device *dev) } struct dma_map_ops vio_dma_mapping_ops = { - .alloc_coherent = vio_dma_iommu_alloc_coherent, - .free_coherent = vio_dma_iommu_free_coherent, - .map_sg = vio_dma_iommu_map_sg, - .unmap_sg = vio_dma_iommu_unmap_sg, - .map_page = vio_dma_iommu_map_page, - .unmap_page = vio_dma_iommu_unmap_page, - .dma_supported = vio_dma_iommu_dma_supported, + .alloc_coherent = vio_dma_iommu_alloc_coherent, + .free_coherent = vio_dma_iommu_free_coherent, + .map_sg = vio_dma_iommu_map_sg, + .unmap_sg = vio_dma_iommu_unmap_sg, + .map_page = vio_dma_iommu_map_page, + .unmap_page = vio_dma_iommu_unmap_page, + .dma_supported = vio_dma_iommu_dma_supported, .get_required_mask = vio_dma_get_required_mask, }; From 7df5659eefad9b6d457ccdee016bd78bd064cfc0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 27 Jun 2011 11:45:16 +0000 Subject: [PATCH 0385/1596] serial/8250: Move UPIO_TSI to powerpc This iotype is only used by the legacy_serial code in powerpc, so the code should live there, rather than be compiled in for every 8250 driver. Signed-off-by: Arnd Bergmann Cc: Benjamin Herrenschmidt Cc: linuxppc-dev@lists.ozlabs.org Cc: Greg Kroah-Hartman Cc: linux-serial@vger.kernel.org Acked-by: David Daney Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/legacy_serial.c | 25 +++++++++++++++++++++++++ drivers/tty/serial/8250.c | 23 ----------------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 2b97b80d6d7d..c7b5afeecaf2 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,24 @@ static struct __initdata of_device_id legacy_serial_parents[] = { static unsigned int legacy_serial_count; static int legacy_serial_console = -1; +static unsigned int tsi_serial_in(struct uart_port *p, int offset) +{ + unsigned int tmp; + offset = offset << p->regshift; + if (offset == UART_IIR) { + tmp = readl(p->membase + (UART_IIR & ~3)); + return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ + } else + return readb(p->membase + offset); +} + +static void tsi_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + if (!((offset == UART_IER) && (value & UART_IER_UUE))) + writeb(value, p->membase + offset); +} + static int __init add_legacy_port(struct device_node *np, int want_index, int iotype, phys_addr_t base, phys_addr_t taddr, unsigned long irq, @@ -102,6 +121,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index, legacy_serial_ports[index].iobase = base; else legacy_serial_ports[index].mapbase = base; + legacy_serial_ports[index].iotype = iotype; legacy_serial_ports[index].uartclk = clock; legacy_serial_ports[index].irq = irq; @@ -112,6 +132,11 @@ static int __init add_legacy_port(struct device_node *np, int want_index, legacy_serial_infos[index].speed = spd ? be32_to_cpup(spd) : 0; legacy_serial_infos[index].irq_check_parent = irq_check_parent; + if (iotype == UPIO_TSI) { + legacy_serial_ports[index].serial_in = tsi_serial_in; + legacy_serial_ports[index].serial_out = tsi_serial_out; + } + printk(KERN_DEBUG "Found legacy serial port %d for %s\n", index, np->full_name); printk(KERN_DEBUG " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n", diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index 7f50999eebc2..610b8e63710d 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c @@ -443,24 +443,6 @@ static void au_serial_out(struct uart_port *p, int offset, int value) __raw_writel(value, p->membase + offset); } -static unsigned int tsi_serial_in(struct uart_port *p, int offset) -{ - unsigned int tmp; - offset = map_8250_in_reg(p, offset) << p->regshift; - if (offset == UART_IIR) { - tmp = readl(p->membase + (UART_IIR & ~3)); - return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ - } else - return readb(p->membase + offset); -} - -static void tsi_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - if (!((offset == UART_IER) && (value & UART_IER_UUE))) - writeb(value, p->membase + offset); -} - /* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */ static inline void dwapb_save_out_value(struct uart_port *p, int offset, int value) @@ -535,11 +517,6 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = au_serial_out; break; - case UPIO_TSI: - p->serial_in = tsi_serial_in; - p->serial_out = tsi_serial_out; - break; - case UPIO_DWAPB: p->serial_in = mem_serial_in; p->serial_out = dwapb_serial_out; From 41151e77a4d96ea138cede6d84c955aa4769ce74 Mon Sep 17 00:00:00 2001 From: Becky Bruce Date: Tue, 28 Jun 2011 09:54:48 +0000 Subject: [PATCH 0386/1596] powerpc: Hugetlb for BookE Enable hugepages on Freescale BookE processors. This allows the kernel to use huge TLB entries to map pages, which can greatly reduce the number of TLB misses and the amount of TLB thrashing experienced by applications with large memory footprints. Care should be taken when using this on FSL processors, as the number of large TLB entries supported by the core is low (16-64) on current processors. The supported set of hugepage sizes include 4m, 16m, 64m, 256m, and 1g. Page sizes larger than the max zone size are called "gigantic" pages and must be allocated on the command line (and cannot be deallocated). This is currently only fully implemented for Freescale 32-bit BookE processors, but there is some infrastructure in the code for 64-bit BooKE. Signed-off-by: Becky Bruce Signed-off-by: David Gibson Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig | 3 +- arch/powerpc/include/asm/hugetlb.h | 63 +++- arch/powerpc/include/asm/mmu-book3e.h | 7 + arch/powerpc/include/asm/mmu-hash64.h | 3 +- arch/powerpc/include/asm/mmu.h | 18 +- arch/powerpc/include/asm/page.h | 31 +- arch/powerpc/include/asm/page_64.h | 11 - arch/powerpc/include/asm/pte-book3e.h | 3 + arch/powerpc/kernel/head_fsl_booke.S | 133 +++++++-- arch/powerpc/mm/Makefile | 1 + arch/powerpc/mm/hash_utils_64.c | 3 - arch/powerpc/mm/hugetlbpage-book3e.c | 121 ++++++++ arch/powerpc/mm/hugetlbpage.c | 379 ++++++++++++++++++++++--- arch/powerpc/mm/init_32.c | 9 + arch/powerpc/mm/mem.c | 5 + arch/powerpc/mm/mmu_context_nohash.c | 5 + arch/powerpc/mm/pgtable.c | 3 +- arch/powerpc/mm/tlb_low_64e.S | 24 +- arch/powerpc/mm/tlb_nohash.c | 46 ++- arch/powerpc/platforms/Kconfig.cputype | 4 +- 20 files changed, 766 insertions(+), 106 deletions(-) create mode 100644 arch/powerpc/mm/hugetlbpage-book3e.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 0a3d5560c9be..62711421cd64 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -429,8 +429,7 @@ config ARCH_POPULATES_NODE_MAP def_bool y config SYS_SUPPORTS_HUGETLBFS - def_bool y - depends on PPC_BOOK3S_64 + bool source "mm/Kconfig" diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h index 5856a66ab404..86004930a78e 100644 --- a/arch/powerpc/include/asm/hugetlb.h +++ b/arch/powerpc/include/asm/hugetlb.h @@ -1,15 +1,60 @@ #ifndef _ASM_POWERPC_HUGETLB_H #define _ASM_POWERPC_HUGETLB_H +#ifdef CONFIG_HUGETLB_PAGE #include +extern struct kmem_cache *hugepte_cache; +extern void __init reserve_hugetlb_gpages(void); + +static inline pte_t *hugepd_page(hugepd_t hpd) +{ + BUG_ON(!hugepd_ok(hpd)); + return (pte_t *)((hpd.pd & ~HUGEPD_SHIFT_MASK) | PD_HUGE); +} + +static inline unsigned int hugepd_shift(hugepd_t hpd) +{ + return hpd.pd & HUGEPD_SHIFT_MASK; +} + +static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr, + unsigned pdshift) +{ + /* + * On 32-bit, we have multiple higher-level table entries that point to + * the same hugepte. Just use the first one since they're all + * identical. So for that case, idx=0. + */ + unsigned long idx = 0; + + pte_t *dir = hugepd_page(*hpdp); +#ifdef CONFIG_PPC64 + idx = (addr & ((1UL << pdshift) - 1)) >> hugepd_shift(*hpdp); +#endif + + return dir + idx; +} + pte_t *huge_pte_offset_and_shift(struct mm_struct *mm, unsigned long addr, unsigned *shift); void flush_dcache_icache_hugepage(struct page *page); +#if defined(CONFIG_PPC_MM_SLICES) || defined(CONFIG_PPC_SUBPAGE_PROT) int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr, unsigned long len); +#else +static inline int is_hugepage_only_range(struct mm_struct *mm, + unsigned long addr, + unsigned long len) +{ + return 0; +} +#endif + +void book3e_hugetlb_preload(struct mm_struct *mm, unsigned long ea, pte_t pte); +void flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr); void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr, unsigned long end, unsigned long floor, @@ -50,8 +95,11 @@ static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1); - return __pte(old); +#ifdef CONFIG_PPC64 + return __pte(pte_update(mm, addr, ptep, ~0UL, 1)); +#else + return __pte(pte_update(ptep, ~0UL, 0)); +#endif } static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, @@ -93,4 +141,15 @@ static inline void arch_release_hugepage(struct page *page) { } +#else /* ! CONFIG_HUGETLB_PAGE */ +static inline void reserve_hugetlb_gpages(void) +{ + pr_err("Cannot reserve gpages without hugetlb enabled\n"); +} +static inline void flush_hugetlb_page(struct vm_area_struct *vma, + unsigned long vmaddr) +{ +} +#endif + #endif /* _ASM_POWERPC_HUGETLB_H */ diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index 3ea0f9a259d8..0260ea5ec3c2 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -66,6 +66,7 @@ #define MAS2_M 0x00000004 #define MAS2_G 0x00000002 #define MAS2_E 0x00000001 +#define MAS2_WIMGE_MASK 0x0000001f #define MAS2_EPN_MASK(size) (~0 << (size + 10)) #define MAS2_VAL(addr, size, flags) ((addr) & MAS2_EPN_MASK(size) | (flags)) @@ -80,6 +81,7 @@ #define MAS3_SW 0x00000004 #define MAS3_UR 0x00000002 #define MAS3_SR 0x00000001 +#define MAS3_BAP_MASK 0x0000003f #define MAS3_SPSIZE 0x0000003e #define MAS3_SPSIZE_SHIFT 1 @@ -212,6 +214,11 @@ typedef struct { unsigned int id; unsigned int active; unsigned long vdso_base; +#ifdef CONFIG_PPC_MM_SLICES + u64 low_slices_psize; /* SLB page size encodings */ + u64 high_slices_psize; /* 4 bits per slice for now */ + u16 user_psize; /* page size index */ +#endif } mm_context_t; /* Page size definitions, common between 32 and 64-bit diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index b445e0af4c2b..db645ec842bd 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h @@ -262,8 +262,7 @@ extern void hash_failure_debug(unsigned long ea, unsigned long access, extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend, unsigned long pstart, unsigned long prot, int psize, int ssize); -extern void add_gpage(unsigned long addr, unsigned long page_size, - unsigned long number_of_pages); +extern void add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages); extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr); extern void hpte_init_native(void); diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 698b30638681..f0145522cfba 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -175,14 +175,16 @@ extern u64 ppc64_rma_size; #define MMU_PAGE_64K_AP 3 /* "Admixed pages" (hash64 only) */ #define MMU_PAGE_256K 4 #define MMU_PAGE_1M 5 -#define MMU_PAGE_8M 6 -#define MMU_PAGE_16M 7 -#define MMU_PAGE_256M 8 -#define MMU_PAGE_1G 9 -#define MMU_PAGE_16G 10 -#define MMU_PAGE_64G 11 -#define MMU_PAGE_COUNT 12 - +#define MMU_PAGE_4M 6 +#define MMU_PAGE_8M 7 +#define MMU_PAGE_16M 8 +#define MMU_PAGE_64M 9 +#define MMU_PAGE_256M 10 +#define MMU_PAGE_1G 11 +#define MMU_PAGE_16G 12 +#define MMU_PAGE_64G 13 + +#define MMU_PAGE_COUNT 14 #if defined(CONFIG_PPC_STD_MMU_64) /* 64-bit classic hash table MMU */ diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index 2cd664ef0a5e..dd9c4fd038e0 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h @@ -36,6 +36,18 @@ #define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT) +#ifndef __ASSEMBLY__ +#ifdef CONFIG_HUGETLB_PAGE +extern unsigned int HPAGE_SHIFT; +#else +#define HPAGE_SHIFT PAGE_SHIFT +#endif +#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) +#define HPAGE_MASK (~(HPAGE_SIZE - 1)) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) +#define HUGE_MAX_HSTATE (MMU_PAGE_COUNT-1) +#endif + /* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */ #define __HAVE_ARCH_GATE_AREA 1 @@ -158,6 +170,24 @@ extern phys_addr_t kernstart_addr; #define is_kernel_addr(x) ((x) >= PAGE_OFFSET) #endif +/* + * Use the top bit of the higher-level page table entries to indicate whether + * the entries we point to contain hugepages. This works because we know that + * the page tables live in kernel space. If we ever decide to support having + * page tables at arbitrary addresses, this breaks and will have to change. + */ +#ifdef CONFIG_PPC64 +#define PD_HUGE 0x8000000000000000 +#else +#define PD_HUGE 0x80000000 +#endif + +/* + * Some number of bits at the level of the page table that points to + * a hugepte are used to encode the size. This masks those bits. + */ +#define HUGEPD_SHIFT_MASK 0x3f + #ifndef __ASSEMBLY__ #undef STRICT_MM_TYPECHECKS @@ -243,7 +273,6 @@ typedef unsigned long pgprot_t; #endif typedef struct { signed long pd; } hugepd_t; -#define HUGEPD_SHIFT_MASK 0x3f #ifdef CONFIG_HUGETLB_PAGE static inline int hugepd_ok(hugepd_t hpd) diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index 9356262fd3cc..fb40ede6bc0d 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h @@ -64,17 +64,6 @@ extern void copy_page(void *to, void *from); /* Log 2 of page table size */ extern u64 ppc64_pft_size; -/* Large pages size */ -#ifdef CONFIG_HUGETLB_PAGE -extern unsigned int HPAGE_SHIFT; -#else -#define HPAGE_SHIFT PAGE_SHIFT -#endif -#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) -#define HPAGE_MASK (~(HPAGE_SIZE - 1)) -#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) -#define HUGE_MAX_HSTATE (MMU_PAGE_COUNT-1) - #endif /* __ASSEMBLY__ */ #ifdef CONFIG_PPC_MM_SLICES diff --git a/arch/powerpc/include/asm/pte-book3e.h b/arch/powerpc/include/asm/pte-book3e.h index 082d515930a2..0156702ba24e 100644 --- a/arch/powerpc/include/asm/pte-book3e.h +++ b/arch/powerpc/include/asm/pte-book3e.h @@ -72,6 +72,9 @@ #define PTE_RPN_SHIFT (24) #endif +#define PTE_WIMGE_SHIFT (19) +#define PTE_BAP_SHIFT (2) + /* On 32-bit, we never clear the top part of the PTE */ #ifdef CONFIG_PPC32 #define _PTE_NONE_MASK 0xffffffff00000000ULL diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 50845924b7d9..4ea9bfbf67e9 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -236,8 +236,24 @@ _ENTRY(__early_start) * if we find the pte (fall through): * r11 is low pte word * r12 is pointer to the pte + * r10 is the pshift from the PGD, if we're a hugepage */ #ifdef CONFIG_PTE_64BIT +#ifdef CONFIG_HUGETLB_PAGE +#define FIND_PTE \ + rlwinm r12, r10, 13, 19, 29; /* Compute pgdir/pmd offset */ \ + lwzx r11, r12, r11; /* Get pgd/pmd entry */ \ + rlwinm. r12, r11, 0, 0, 20; /* Extract pt base address */ \ + blt 1000f; /* Normal non-huge page */ \ + beq 2f; /* Bail if no table */ \ + oris r11, r11, PD_HUGE@h; /* Put back address bit */ \ + andi. r10, r11, HUGEPD_SHIFT_MASK@l; /* extract size field */ \ + xor r12, r10, r11; /* drop size bits from pointer */ \ + b 1001f; \ +1000: rlwimi r12, r10, 23, 20, 28; /* Compute pte address */ \ + li r10, 0; /* clear r10 */ \ +1001: lwz r11, 4(r12); /* Get pte entry */ +#else #define FIND_PTE \ rlwinm r12, r10, 13, 19, 29; /* Compute pgdir/pmd offset */ \ lwzx r11, r12, r11; /* Get pgd/pmd entry */ \ @@ -245,7 +261,8 @@ _ENTRY(__early_start) beq 2f; /* Bail if no table */ \ rlwimi r12, r10, 23, 20, 28; /* Compute pte address */ \ lwz r11, 4(r12); /* Get pte entry */ -#else +#endif /* HUGEPAGE */ +#else /* !PTE_64BIT */ #define FIND_PTE \ rlwimi r11, r10, 12, 20, 29; /* Create L1 (pgdir/pmd) address */ \ lwz r11, 0(r11); /* Get L1 entry */ \ @@ -402,8 +419,8 @@ interrupt_base: #ifdef CONFIG_PTE_64BIT #ifdef CONFIG_SMP - subf r10,r11,r12 /* create false data dep */ - lwzx r13,r11,r10 /* Get upper pte bits */ + subf r13,r11,r12 /* create false data dep */ + lwzx r13,r11,r13 /* Get upper pte bits */ #else lwz r13,0(r12) /* Get upper pte bits */ #endif @@ -483,8 +500,8 @@ interrupt_base: #ifdef CONFIG_PTE_64BIT #ifdef CONFIG_SMP - subf r10,r11,r12 /* create false data dep */ - lwzx r13,r11,r10 /* Get upper pte bits */ + subf r13,r11,r12 /* create false data dep */ + lwzx r13,r11,r13 /* Get upper pte bits */ #else lwz r13,0(r12) /* Get upper pte bits */ #endif @@ -548,7 +565,7 @@ interrupt_base: /* * Both the instruction and data TLB miss get to this * point to load the TLB. - * r10 - available to use + * r10 - tsize encoding (if HUGETLB_PAGE) or available to use * r11 - TLB (info from Linux PTE) * r12 - available to use * r13 - upper bits of PTE (if PTE_64BIT) or available to use @@ -558,21 +575,73 @@ interrupt_base: * Upon exit, we reload everything and RFI. */ finish_tlb_load: +#ifdef CONFIG_HUGETLB_PAGE + cmpwi 6, r10, 0 /* check for huge page */ + beq 6, finish_tlb_load_cont /* !huge */ + + /* Alas, we need more scratch registers for hugepages */ + mfspr r12, SPRN_SPRG_THREAD + stw r14, THREAD_NORMSAVE(4)(r12) + stw r15, THREAD_NORMSAVE(5)(r12) + stw r16, THREAD_NORMSAVE(6)(r12) + stw r17, THREAD_NORMSAVE(7)(r12) + + /* Get the next_tlbcam_idx percpu var */ +#ifdef CONFIG_SMP + lwz r12, THREAD_INFO-THREAD(r12) + lwz r15, TI_CPU(r12) + lis r14, __per_cpu_offset@h + ori r14, r14, __per_cpu_offset@l + rlwinm r15, r15, 2, 0, 29 + lwzx r16, r14, r15 +#else + li r16, 0 +#endif + lis r17, next_tlbcam_idx@h + ori r17, r17, next_tlbcam_idx@l + add r17, r17, r16 /* r17 = *next_tlbcam_idx */ + lwz r15, 0(r17) /* r15 = next_tlbcam_idx */ + + lis r14, MAS0_TLBSEL(1)@h /* select TLB1 (TLBCAM) */ + rlwimi r14, r15, 16, 4, 15 /* next_tlbcam_idx entry */ + mtspr SPRN_MAS0, r14 + + /* Extract TLB1CFG(NENTRY) */ + mfspr r16, SPRN_TLB1CFG + andi. r16, r16, 0xfff + + /* Update next_tlbcam_idx, wrapping when necessary */ + addi r15, r15, 1 + cmpw r15, r16 + blt 100f + lis r14, tlbcam_index@h + ori r14, r14, tlbcam_index@l + lwz r15, 0(r14) +100: stw r15, 0(r17) + + /* + * Calc MAS1_TSIZE from r10 (which has pshift encoded) + * tlb_enc = (pshift - 10). + */ + subi r15, r10, 10 + mfspr r16, SPRN_MAS1 + rlwimi r16, r15, 7, 20, 24 + mtspr SPRN_MAS1, r16 + + /* copy the pshift for use later */ + mr r14, r10 + + /* fall through */ + +#endif /* CONFIG_HUGETLB_PAGE */ + /* * We set execute, because we don't have the granularity to * properly set this at the page level (Linux problem). * Many of these bits are software only. Bits we don't set * here we (properly should) assume have the appropriate value. */ - - mfspr r12, SPRN_MAS2 -#ifdef CONFIG_PTE_64BIT - rlwimi r12, r11, 32-19, 27, 31 /* extract WIMGE from pte */ -#else - rlwimi r12, r11, 26, 27, 31 /* extract WIMGE from pte */ -#endif - mtspr SPRN_MAS2, r12 - +finish_tlb_load_cont: #ifdef CONFIG_PTE_64BIT rlwinm r12, r11, 32-2, 26, 31 /* Move in perm bits */ andi. r10, r11, _PAGE_DIRTY @@ -581,22 +650,40 @@ finish_tlb_load: andc r12, r12, r10 1: rlwimi r12, r13, 20, 0, 11 /* grab RPN[32:43] */ rlwimi r12, r11, 20, 12, 19 /* grab RPN[44:51] */ - mtspr SPRN_MAS3, r12 +2: mtspr SPRN_MAS3, r12 BEGIN_MMU_FTR_SECTION srwi r10, r13, 12 /* grab RPN[12:31] */ mtspr SPRN_MAS7, r10 END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS) #else li r10, (_PAGE_EXEC | _PAGE_PRESENT) + mr r13, r11 rlwimi r10, r11, 31, 29, 29 /* extract _PAGE_DIRTY into SW */ and r12, r11, r10 andi. r10, r11, _PAGE_USER /* Test for _PAGE_USER */ slwi r10, r12, 1 or r10, r10, r12 iseleq r12, r12, r10 - rlwimi r11, r12, 0, 20, 31 /* Extract RPN from PTE and merge with perms */ - mtspr SPRN_MAS3, r11 + rlwimi r13, r12, 0, 20, 31 /* Get RPN from PTE, merge w/ perms */ + mtspr SPRN_MAS3, r13 #endif + + mfspr r12, SPRN_MAS2 +#ifdef CONFIG_PTE_64BIT + rlwimi r12, r11, 32-19, 27, 31 /* extract WIMGE from pte */ +#else + rlwimi r12, r11, 26, 27, 31 /* extract WIMGE from pte */ +#endif +#ifdef CONFIG_HUGETLB_PAGE + beq 6, 3f /* don't mask if page isn't huge */ + li r13, 1 + slw r13, r13, r14 + subi r13, r13, 1 + rlwinm r13, r13, 0, 0, 19 /* bottom bits used for WIMGE/etc */ + andc r12, r12, r13 /* mask off ea bits within the page */ +#endif +3: mtspr SPRN_MAS2, r12 + #ifdef CONFIG_E200 /* Round robin TLB1 entries assignment */ mfspr r12, SPRN_MAS0 @@ -622,11 +709,19 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS) mtspr SPRN_MAS0,r12 #endif /* CONFIG_E200 */ +tlb_write_entry: tlbwe /* Done...restore registers and get out of here. */ mfspr r10, SPRN_SPRG_THREAD - lwz r11, THREAD_NORMSAVE(3)(r10) +#ifdef CONFIG_HUGETLB_PAGE + beq 6, 8f /* skip restore for 4k page faults */ + lwz r14, THREAD_NORMSAVE(4)(r10) + lwz r15, THREAD_NORMSAVE(5)(r10) + lwz r16, THREAD_NORMSAVE(6)(r10) + lwz r17, THREAD_NORMSAVE(7)(r10) +#endif +8: lwz r11, THREAD_NORMSAVE(3)(r10) mtcr r11 lwz r13, THREAD_NORMSAVE(2)(r10) lwz r12, THREAD_NORMSAVE(1)(r10) diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index bdca46e08382..991ee813d2a8 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_MM_SLICES) += slice.o ifeq ($(CONFIG_HUGETLB_PAGE),y) obj-y += hugetlbpage.o obj-$(CONFIG_PPC_STD_MMU_64) += hugetlbpage-hash64.o +obj-$(CONFIG_PPC_BOOK3E_MMU) += hugetlbpage-book3e.o endif obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 26b2872b3d00..1f8b2a05e3d0 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -105,9 +105,6 @@ int mmu_kernel_ssize = MMU_SEGSIZE_256M; int mmu_highuser_ssize = MMU_SEGSIZE_256M; u16 mmu_slb_size = 64; EXPORT_SYMBOL_GPL(mmu_slb_size); -#ifdef CONFIG_HUGETLB_PAGE -unsigned int HPAGE_SHIFT; -#endif #ifdef CONFIG_PPC_64K_PAGES int mmu_ci_restrictions; #endif diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c new file mode 100644 index 000000000000..1295b7c1cdac --- /dev/null +++ b/arch/powerpc/mm/hugetlbpage-book3e.c @@ -0,0 +1,121 @@ +/* + * PPC Huge TLB Page Support for Book3E MMU + * + * Copyright (C) 2009 David Gibson, IBM Corporation. + * Copyright (C) 2011 Becky Bruce, Freescale Semiconductor + * + */ +#include +#include + +static inline int mmu_get_tsize(int psize) +{ + return mmu_psize_defs[psize].enc; +} + +static inline int book3e_tlb_exists(unsigned long ea, unsigned long pid) +{ + int found = 0; + + mtspr(SPRN_MAS6, pid << 16); + if (mmu_has_feature(MMU_FTR_USE_TLBRSRV)) { + asm volatile( + "li %0,0\n" + "tlbsx. 0,%1\n" + "bne 1f\n" + "li %0,1\n" + "1:\n" + : "=&r"(found) : "r"(ea)); + } else { + asm volatile( + "tlbsx 0,%1\n" + "mfspr %0,0x271\n" + "srwi %0,%0,31\n" + : "=&r"(found) : "r"(ea)); + } + + return found; +} + +void book3e_hugetlb_preload(struct mm_struct *mm, unsigned long ea, pte_t pte) +{ + unsigned long mas1, mas2; + u64 mas7_3; + unsigned long psize, tsize, shift; + unsigned long flags; + +#ifdef CONFIG_PPC_FSL_BOOK3E + int index, lz, ncams; + struct vm_area_struct *vma; +#endif + + if (unlikely(is_kernel_addr(ea))) + return; + +#ifdef CONFIG_MM_SLICES + psize = mmu_get_tsize(get_slice_psize(mm, ea)); + tsize = mmu_get_psize(psize); + shift = mmu_psize_defs[psize].shift; +#else + vma = find_vma(mm, ea); + psize = vma_mmu_pagesize(vma); /* returns actual size in bytes */ + asm (PPC_CNTLZL "%0,%1" : "=r" (lz) : "r" (psize)); + shift = 31 - lz; + tsize = 21 - lz; +#endif + + /* + * We can't be interrupted while we're setting up the MAS + * regusters or after we've confirmed that no tlb exists. + */ + local_irq_save(flags); + + if (unlikely(book3e_tlb_exists(ea, mm->context.id))) { + local_irq_restore(flags); + return; + } + +#ifdef CONFIG_PPC_FSL_BOOK3E + ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; + + /* We have to use the CAM(TLB1) on FSL parts for hugepages */ + index = __get_cpu_var(next_tlbcam_idx); + mtspr(SPRN_MAS0, MAS0_ESEL(index) | MAS0_TLBSEL(1)); + + /* Just round-robin the entries and wrap when we hit the end */ + if (unlikely(index == ncams - 1)) + __get_cpu_var(next_tlbcam_idx) = tlbcam_index; + else + __get_cpu_var(next_tlbcam_idx)++; +#endif + mas1 = MAS1_VALID | MAS1_TID(mm->context.id) | MAS1_TSIZE(tsize); + mas2 = ea & ~((1UL << shift) - 1); + mas2 |= (pte_val(pte) >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK; + mas7_3 = (u64)pte_pfn(pte) << PAGE_SHIFT; + mas7_3 |= (pte_val(pte) >> PTE_BAP_SHIFT) & MAS3_BAP_MASK; + if (!pte_dirty(pte)) + mas7_3 &= ~(MAS3_SW|MAS3_UW); + + mtspr(SPRN_MAS1, mas1); + mtspr(SPRN_MAS2, mas2); + + if (mmu_has_feature(MMU_FTR_USE_PAIRED_MAS)) { + mtspr(SPRN_MAS7_MAS3, mas7_3); + } else { + mtspr(SPRN_MAS7, upper_32_bits(mas7_3)); + mtspr(SPRN_MAS3, lower_32_bits(mas7_3)); + } + + asm volatile ("tlbwe"); + + local_irq_restore(flags); +} + +void flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + struct hstate *hstate = hstate_file(vma->vm_file); + unsigned long tsize = huge_page_shift(hstate) - 10; + + __flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr, tsize, 0); + +} diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 0b9a5c1901b9..3a5f59dcbb33 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -1,7 +1,8 @@ /* - * PPC64 (POWER4) Huge TLB Page Support for Kernel. + * PPC Huge TLB Page Support for Kernel. * * Copyright (C) 2003 David Gibson, IBM Corporation. + * Copyright (C) 2011 Becky Bruce, Freescale Semiconductor * * Based on the IA-32 version: * Copyright (C) 2002, Rohit Seth @@ -11,24 +12,39 @@ #include #include #include +#include +#include +#include #include #include #include +#include #define PAGE_SHIFT_64K 16 #define PAGE_SHIFT_16M 24 #define PAGE_SHIFT_16G 34 -#define MAX_NUMBER_GPAGES 1024 +unsigned int HPAGE_SHIFT; -/* Tracks the 16G pages after the device tree is scanned and before the - * huge_boot_pages list is ready. */ -static unsigned long gpage_freearray[MAX_NUMBER_GPAGES]; +/* + * Tracks gpages after the device tree is scanned and before the + * huge_boot_pages list is ready. On 64-bit implementations, this is + * just used to track 16G pages and so is a single array. 32-bit + * implementations may have more than one gpage size due to limitations + * of the memory allocators, so we need multiple arrays + */ +#ifdef CONFIG_PPC64 +#define MAX_NUMBER_GPAGES 1024 +static u64 gpage_freearray[MAX_NUMBER_GPAGES]; static unsigned nr_gpages; - -/* Flag to mark huge PD pointers. This means pmd_bad() and pud_bad() - * will choke on pointers to hugepte tables, which is handy for - * catching screwups early. */ +#else +#define MAX_NUMBER_GPAGES 128 +struct psize_gpages { + u64 gpage_list[MAX_NUMBER_GPAGES]; + unsigned int nr_gpages; +}; +static struct psize_gpages gpage_freearray[MMU_PAGE_COUNT]; +#endif static inline int shift_to_mmu_psize(unsigned int shift) { @@ -49,25 +65,6 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize) #define hugepd_none(hpd) ((hpd).pd == 0) -static inline pte_t *hugepd_page(hugepd_t hpd) -{ - BUG_ON(!hugepd_ok(hpd)); - return (pte_t *)((hpd.pd & ~HUGEPD_SHIFT_MASK) | 0xc000000000000000); -} - -static inline unsigned int hugepd_shift(hugepd_t hpd) -{ - return hpd.pd & HUGEPD_SHIFT_MASK; -} - -static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr, unsigned pdshift) -{ - unsigned long idx = (addr & ((1UL << pdshift) - 1)) >> hugepd_shift(*hpdp); - pte_t *dir = hugepd_page(*hpdp); - - return dir + idx; -} - pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift) { pgd_t *pg; @@ -93,7 +90,7 @@ pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift if (is_hugepd(pm)) hpdp = (hugepd_t *)pm; else if (!pmd_none(*pm)) { - return pte_offset_map(pm, ea); + return pte_offset_kernel(pm, ea); } } } @@ -114,8 +111,18 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, unsigned long address, unsigned pdshift, unsigned pshift) { - pte_t *new = kmem_cache_zalloc(PGT_CACHE(pdshift - pshift), - GFP_KERNEL|__GFP_REPEAT); + struct kmem_cache *cachep; + pte_t *new; + +#ifdef CONFIG_PPC64 + cachep = PGT_CACHE(pdshift - pshift); +#else + int i; + int num_hugepd = 1 << (pshift - pdshift); + cachep = hugepte_cache; +#endif + + new = kmem_cache_zalloc(cachep, GFP_KERNEL|__GFP_REPEAT); BUG_ON(pshift > HUGEPD_SHIFT_MASK); BUG_ON((unsigned long)new & HUGEPD_SHIFT_MASK); @@ -124,10 +131,31 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, return -ENOMEM; spin_lock(&mm->page_table_lock); +#ifdef CONFIG_PPC64 if (!hugepd_none(*hpdp)) - kmem_cache_free(PGT_CACHE(pdshift - pshift), new); + kmem_cache_free(cachep, new); else - hpdp->pd = ((unsigned long)new & ~0x8000000000000000) | pshift; + hpdp->pd = ((unsigned long)new & ~PD_HUGE) | pshift; +#else + /* + * We have multiple higher-level entries that point to the same + * actual pte location. Fill in each as we go and backtrack on error. + * We need all of these so the DTLB pgtable walk code can find the + * right higher-level entry without knowing if it's a hugepage or not. + */ + for (i = 0; i < num_hugepd; i++, hpdp++) { + if (unlikely(!hugepd_none(*hpdp))) + break; + else + hpdp->pd = ((unsigned long)new & ~PD_HUGE) | pshift; + } + /* If we bailed from the for loop early, an error occurred, clean up */ + if (i < num_hugepd) { + for (i = i - 1 ; i >= 0; i--, hpdp--) + hpdp->pd = 0; + kmem_cache_free(cachep, new); + } +#endif spin_unlock(&mm->page_table_lock); return 0; } @@ -169,11 +197,132 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz return hugepte_offset(hpdp, addr, pdshift); } +#ifdef CONFIG_PPC32 /* Build list of addresses of gigantic pages. This function is used in early * boot before the buddy or bootmem allocator is setup. */ -void add_gpage(unsigned long addr, unsigned long page_size, - unsigned long number_of_pages) +void add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages) +{ + unsigned int idx = shift_to_mmu_psize(__ffs(page_size)); + int i; + + if (addr == 0) + return; + + gpage_freearray[idx].nr_gpages = number_of_pages; + + for (i = 0; i < number_of_pages; i++) { + gpage_freearray[idx].gpage_list[i] = addr; + addr += page_size; + } +} + +/* + * Moves the gigantic page addresses from the temporary list to the + * huge_boot_pages list. + */ +int alloc_bootmem_huge_page(struct hstate *hstate) +{ + struct huge_bootmem_page *m; + int idx = shift_to_mmu_psize(hstate->order + PAGE_SHIFT); + int nr_gpages = gpage_freearray[idx].nr_gpages; + + if (nr_gpages == 0) + return 0; + +#ifdef CONFIG_HIGHMEM + /* + * If gpages can be in highmem we can't use the trick of storing the + * data structure in the page; allocate space for this + */ + m = alloc_bootmem(sizeof(struct huge_bootmem_page)); + m->phys = gpage_freearray[idx].gpage_list[--nr_gpages]; +#else + m = phys_to_virt(gpage_freearray[idx].gpage_list[--nr_gpages]); +#endif + + list_add(&m->list, &huge_boot_pages); + gpage_freearray[idx].nr_gpages = nr_gpages; + gpage_freearray[idx].gpage_list[nr_gpages] = 0; + m->hstate = hstate; + + return 1; +} +/* + * Scan the command line hugepagesz= options for gigantic pages; store those in + * a list that we use to allocate the memory once all options are parsed. + */ + +unsigned long gpage_npages[MMU_PAGE_COUNT]; + +static int __init do_gpage_early_setup(char *param, char *val) +{ + static phys_addr_t size; + unsigned long npages; + + /* + * The hugepagesz and hugepages cmdline options are interleaved. We + * use the size variable to keep track of whether or not this was done + * properly and skip over instances where it is incorrect. Other + * command-line parsing code will issue warnings, so we don't need to. + * + */ + if ((strcmp(param, "default_hugepagesz") == 0) || + (strcmp(param, "hugepagesz") == 0)) { + size = memparse(val, NULL); + } else if (strcmp(param, "hugepages") == 0) { + if (size != 0) { + if (sscanf(val, "%lu", &npages) <= 0) + npages = 0; + gpage_npages[shift_to_mmu_psize(__ffs(size))] = npages; + size = 0; + } + } + return 0; +} + + +/* + * This function allocates physical space for pages that are larger than the + * buddy allocator can handle. We want to allocate these in highmem because + * the amount of lowmem is limited. This means that this function MUST be + * called before lowmem_end_addr is set up in MMU_init() in order for the lmb + * allocate to grab highmem. + */ +void __init reserve_hugetlb_gpages(void) +{ + static __initdata char cmdline[COMMAND_LINE_SIZE]; + phys_addr_t size, base; + int i; + + strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE); + parse_args("hugetlb gpages", cmdline, NULL, 0, &do_gpage_early_setup); + + /* + * Walk gpage list in reverse, allocating larger page sizes first. + * Skip over unsupported sizes, or sizes that have 0 gpages allocated. + * When we reach the point in the list where pages are no longer + * considered gpages, we're done. + */ + for (i = MMU_PAGE_COUNT-1; i >= 0; i--) { + if (mmu_psize_defs[i].shift == 0 || gpage_npages[i] == 0) + continue; + else if (mmu_psize_to_shift(i) < (MAX_ORDER + PAGE_SHIFT)) + break; + + size = (phys_addr_t)(1ULL << mmu_psize_to_shift(i)); + base = memblock_alloc_base(size * gpage_npages[i], size, + MEMBLOCK_ALLOC_ANYWHERE); + add_gpage(base, size, gpage_npages[i]); + } +} + +#else /* PPC64 */ + +/* Build list of addresses of gigantic pages. This function is used in early + * boot before the buddy or bootmem allocator is setup. + */ +void add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages) { if (!addr) return; @@ -199,19 +348,79 @@ int alloc_bootmem_huge_page(struct hstate *hstate) m->hstate = hstate; return 1; } +#endif int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) { return 0; } +#ifdef CONFIG_PPC32 +#define HUGEPD_FREELIST_SIZE \ + ((PAGE_SIZE - sizeof(struct hugepd_freelist)) / sizeof(pte_t)) + +struct hugepd_freelist { + struct rcu_head rcu; + unsigned int index; + void *ptes[0]; +}; + +static DEFINE_PER_CPU(struct hugepd_freelist *, hugepd_freelist_cur); + +static void hugepd_free_rcu_callback(struct rcu_head *head) +{ + struct hugepd_freelist *batch = + container_of(head, struct hugepd_freelist, rcu); + unsigned int i; + + for (i = 0; i < batch->index; i++) + kmem_cache_free(hugepte_cache, batch->ptes[i]); + + free_page((unsigned long)batch); +} + +static void hugepd_free(struct mmu_gather *tlb, void *hugepte) +{ + struct hugepd_freelist **batchp; + + batchp = &__get_cpu_var(hugepd_freelist_cur); + + if (atomic_read(&tlb->mm->mm_users) < 2 || + cpumask_equal(mm_cpumask(tlb->mm), + cpumask_of(smp_processor_id()))) { + kmem_cache_free(hugepte_cache, hugepte); + return; + } + + if (*batchp == NULL) { + *batchp = (struct hugepd_freelist *)__get_free_page(GFP_ATOMIC); + (*batchp)->index = 0; + } + + (*batchp)->ptes[(*batchp)->index++] = hugepte; + if ((*batchp)->index == HUGEPD_FREELIST_SIZE) { + call_rcu_sched(&(*batchp)->rcu, hugepd_free_rcu_callback); + *batchp = NULL; + } +} +#endif + static void free_hugepd_range(struct mmu_gather *tlb, hugepd_t *hpdp, int pdshift, unsigned long start, unsigned long end, unsigned long floor, unsigned long ceiling) { pte_t *hugepte = hugepd_page(*hpdp); - unsigned shift = hugepd_shift(*hpdp); + int i; + unsigned long pdmask = ~((1UL << pdshift) - 1); + unsigned int num_hugepd = 1; + +#ifdef CONFIG_PPC64 + unsigned int shift = hugepd_shift(*hpdp); +#else + /* Note: On 32-bit the hpdp may be the first of several */ + num_hugepd = (1 << (hugepd_shift(*hpdp) - pdshift)); +#endif start &= pdmask; if (start < floor) @@ -224,9 +433,15 @@ static void free_hugepd_range(struct mmu_gather *tlb, hugepd_t *hpdp, int pdshif if (end - 1 > ceiling - 1) return; - hpdp->pd = 0; + for (i = 0; i < num_hugepd; i++, hpdp++) + hpdp->pd = 0; + tlb->need_flush = 1; +#ifdef CONFIG_PPC64 pgtable_free_tlb(tlb, hugepte, pdshift - shift); +#else + hugepd_free(tlb, hugepte); +#endif } static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud, @@ -331,18 +546,27 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb, * too. */ - pgd = pgd_offset(tlb->mm, addr); do { next = pgd_addr_end(addr, end); + pgd = pgd_offset(tlb->mm, addr); if (!is_hugepd(pgd)) { if (pgd_none_or_clear_bad(pgd)) continue; hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling); } else { +#ifdef CONFIG_PPC32 + /* + * Increment next by the size of the huge mapping since + * on 32-bit there may be more than one entry at the pgd + * level for a single hugepage, but all of them point to + * the same kmem cache that holds the hugepte. + */ + next = addr + (1 << hugepd_shift(*(hugepd_t *)pgd)); +#endif free_hugepd_range(tlb, (hugepd_t *)pgd, PGDIR_SHIFT, addr, next, floor, ceiling); } - } while (pgd++, addr = next, addr != end); + } while (addr = next, addr != end); } struct page * @@ -466,17 +690,35 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { +#ifdef CONFIG_MM_SLICES struct hstate *hstate = hstate_file(file); int mmu_psize = shift_to_mmu_psize(huge_page_shift(hstate)); return slice_get_unmapped_area(addr, len, flags, mmu_psize, 1, 0); +#else + return get_unmapped_area(file, addr, len, pgoff, flags); +#endif } unsigned long vma_mmu_pagesize(struct vm_area_struct *vma) { +#ifdef CONFIG_MM_SLICES unsigned int psize = get_slice_psize(vma->vm_mm, vma->vm_start); return 1UL << mmu_psize_to_shift(psize); +#else + if (!is_vm_hugetlb_page(vma)) + return PAGE_SIZE; + + return huge_page_size(hstate_vma(vma)); +#endif +} + +static inline bool is_power_of_4(unsigned long x) +{ + if (is_power_of_2(x)) + return (__ilog2(x) % 2) ? false : true; + return false; } static int __init add_huge_page_size(unsigned long long size) @@ -486,9 +728,14 @@ static int __init add_huge_page_size(unsigned long long size) /* Check that it is a page size supported by the hardware and * that it fits within pagetable and slice limits. */ +#ifdef CONFIG_PPC_FSL_BOOK3E + if ((size < PAGE_SIZE) || !is_power_of_4(size)) + return -EINVAL; +#else if (!is_power_of_2(size) || (shift > SLICE_HIGH_SHIFT) || (shift <= PAGE_SHIFT)) return -EINVAL; +#endif if ((mmu_psize = shift_to_mmu_psize(shift)) < 0) return -EINVAL; @@ -525,6 +772,46 @@ static int __init hugepage_setup_sz(char *str) } __setup("hugepagesz=", hugepage_setup_sz); +#ifdef CONFIG_FSL_BOOKE +struct kmem_cache *hugepte_cache; +static int __init hugetlbpage_init(void) +{ + int psize; + + for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { + unsigned shift; + + if (!mmu_psize_defs[psize].shift) + continue; + + shift = mmu_psize_to_shift(psize); + + /* Don't treat normal page sizes as huge... */ + if (shift != PAGE_SHIFT) + if (add_huge_page_size(1ULL << shift) < 0) + continue; + } + + /* + * Create a kmem cache for hugeptes. The bottom bits in the pte have + * size information encoded in them, so align them to allow this + */ + hugepte_cache = kmem_cache_create("hugepte-cache", sizeof(pte_t), + HUGEPD_SHIFT_MASK + 1, 0, NULL); + if (hugepte_cache == NULL) + panic("%s: Unable to create kmem cache for hugeptes\n", + __func__); + + /* Default hpage size = 4M */ + if (mmu_psize_defs[MMU_PAGE_4M].shift) + HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_4M].shift; + else + panic("%s: Unable to set default huge page size\n", __func__); + + + return 0; +} +#else static int __init hugetlbpage_init(void) { int psize; @@ -567,15 +854,23 @@ static int __init hugetlbpage_init(void) return 0; } - +#endif module_init(hugetlbpage_init); void flush_dcache_icache_hugepage(struct page *page) { int i; + void *start; BUG_ON(!PageCompound(page)); - for (i = 0; i < (1UL << compound_order(page)); i++) - __flush_dcache_icache(page_address(page+i)); + for (i = 0; i < (1UL << compound_order(page)); i++) { + if (!PageHighMem(page)) { + __flush_dcache_icache(page_address(page+i)); + } else { + start = kmap_atomic(page+i, KM_PPC_SYNC_ICACHE); + __flush_dcache_icache(start); + kunmap_atomic(start, KM_PPC_SYNC_ICACHE); + } + } } diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index c77fef56dad6..161cefde5c15 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -44,6 +46,7 @@ #include #include #include +#include #include "mmu_decl.h" @@ -123,6 +126,12 @@ void __init MMU_init(void) /* parse args from command line */ MMU_setup(); + /* + * Reserve gigantic pages for hugetlb. This MUST occur before + * lowmem_end_addr is initialized below. + */ + reserve_hugetlb_gpages(); + if (memblock.memory.cnt > 1) { #ifndef CONFIG_WII memblock.memory.cnt = 1; diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index c781bbcf7338..ad9cf49dfb89 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -548,4 +548,9 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, return; hash_preload(vma->vm_mm, address, access, trap); #endif /* CONFIG_PPC_STD_MMU */ +#if (defined(CONFIG_PPC_BOOK3E_64) || defined(CONFIG_PPC_FSL_BOOK3E)) \ + && defined(CONFIG_HUGETLB_PAGE) + if (is_vm_hugetlb_page(vma)) + book3e_hugetlb_preload(vma->vm_mm, address, *ptep); +#endif } diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c index 336807de550e..5b63bd3da4a9 100644 --- a/arch/powerpc/mm/mmu_context_nohash.c +++ b/arch/powerpc/mm/mmu_context_nohash.c @@ -292,6 +292,11 @@ int init_new_context(struct task_struct *t, struct mm_struct *mm) mm->context.id = MMU_NO_CONTEXT; mm->context.active = 0; +#ifdef CONFIG_PPC_MM_SLICES + if (slice_mm_new_context(mm)) + slice_set_user_psize(mm, mmu_virtual_psize); +#endif + return 0; } diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index af40c8768a78..214130a4edc6 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -212,7 +213,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, entry = set_access_flags_filter(entry, vma, dirty); changed = !pte_same(*(ptep), entry); if (changed) { - if (!(vma->vm_flags & VM_HUGETLB)) + if (!is_vm_hugetlb_page(vma)) assert_pte_locked(vma->vm_mm, address); __ptep_set_access_flags(ptep, entry); flush_tlb_page_nohash(vma, address); diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S index 4ebb34bc01d6..dc4a5f385e41 100644 --- a/arch/powerpc/mm/tlb_low_64e.S +++ b/arch/powerpc/mm/tlb_low_64e.S @@ -553,24 +553,24 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_TLBRSRV) rldicl r11,r16,64-VPTE_PGD_SHIFT,64-PGD_INDEX_SIZE-3 clrrdi r10,r11,3 ldx r15,r10,r15 - cmpldi cr0,r15,0 - beq virt_page_table_tlb_miss_fault + cmpdi cr0,r15,0 + bge virt_page_table_tlb_miss_fault #ifndef CONFIG_PPC_64K_PAGES /* Get to PUD entry */ rldicl r11,r16,64-VPTE_PUD_SHIFT,64-PUD_INDEX_SIZE-3 clrrdi r10,r11,3 ldx r15,r10,r15 - cmpldi cr0,r15,0 - beq virt_page_table_tlb_miss_fault + cmpdi cr0,r15,0 + bge virt_page_table_tlb_miss_fault #endif /* CONFIG_PPC_64K_PAGES */ /* Get to PMD entry */ rldicl r11,r16,64-VPTE_PMD_SHIFT,64-PMD_INDEX_SIZE-3 clrrdi r10,r11,3 ldx r15,r10,r15 - cmpldi cr0,r15,0 - beq virt_page_table_tlb_miss_fault + cmpdi cr0,r15,0 + bge virt_page_table_tlb_miss_fault /* Ok, we're all right, we can now create a kernel translation for * a 4K or 64K page from r16 -> r15. @@ -802,24 +802,24 @@ htw_tlb_miss: rldicl r11,r16,64-(PGDIR_SHIFT-3),64-PGD_INDEX_SIZE-3 clrrdi r10,r11,3 ldx r15,r10,r15 - cmpldi cr0,r15,0 - beq htw_tlb_miss_fault + cmpdi cr0,r15,0 + bge htw_tlb_miss_fault #ifndef CONFIG_PPC_64K_PAGES /* Get to PUD entry */ rldicl r11,r16,64-(PUD_SHIFT-3),64-PUD_INDEX_SIZE-3 clrrdi r10,r11,3 ldx r15,r10,r15 - cmpldi cr0,r15,0 - beq htw_tlb_miss_fault + cmpdi cr0,r15,0 + bge htw_tlb_miss_fault #endif /* CONFIG_PPC_64K_PAGES */ /* Get to PMD entry */ rldicl r11,r16,64-(PMD_SHIFT-3),64-PMD_INDEX_SIZE-3 clrrdi r10,r11,3 ldx r15,r10,r15 - cmpldi cr0,r15,0 - beq htw_tlb_miss_fault + cmpdi cr0,r15,0 + bge htw_tlb_miss_fault /* Ok, we're all right, we can now create an indirect entry for * a 1M or 256M page. diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index d32ec643c231..afc95c7304ae 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -36,14 +36,49 @@ #include #include #include +#include #include #include #include +#include #include "mmu_decl.h" -#ifdef CONFIG_PPC_BOOK3E +/* + * This struct lists the sw-supported page sizes. The hardawre MMU may support + * other sizes not listed here. The .ind field is only used on MMUs that have + * indirect page table entries. + */ +#ifdef CONFIG_PPC_BOOK3E_MMU +#ifdef CONFIG_FSL_BOOKE +struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { + [MMU_PAGE_4K] = { + .shift = 12, + .enc = BOOK3E_PAGESZ_4K, + }, + [MMU_PAGE_4M] = { + .shift = 22, + .enc = BOOK3E_PAGESZ_4M, + }, + [MMU_PAGE_16M] = { + .shift = 24, + .enc = BOOK3E_PAGESZ_16M, + }, + [MMU_PAGE_64M] = { + .shift = 26, + .enc = BOOK3E_PAGESZ_64M, + }, + [MMU_PAGE_256M] = { + .shift = 28, + .enc = BOOK3E_PAGESZ_256M, + }, + [MMU_PAGE_1G] = { + .shift = 30, + .enc = BOOK3E_PAGESZ_1GB, + }, +}; +#else struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { [MMU_PAGE_4K] = { .shift = 12, @@ -77,6 +112,8 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = { .enc = BOOK3E_PAGESZ_1GB, }, }; +#endif /* CONFIG_FSL_BOOKE */ + static inline int mmu_get_tsize(int psize) { return mmu_psize_defs[psize].enc; @@ -87,7 +124,7 @@ static inline int mmu_get_tsize(int psize) /* This isn't used on !Book3E for now */ return 0; } -#endif +#endif /* CONFIG_PPC_BOOK3E_MMU */ /* The variables below are currently only used on 64-bit Book3E * though this will probably be made common with other nohash @@ -266,6 +303,11 @@ void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { +#ifdef CONFIG_HUGETLB_PAGE + if (is_vm_hugetlb_page(vma)) + flush_hugetlb_page(vma, vmaddr); +#endif + __flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr, mmu_get_tsize(mmu_virtual_psize), 0); } diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index e06e39589a09..a85990c886e9 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -69,6 +69,7 @@ config PPC_BOOK3S_64 bool "Server processors" select PPC_FPU select PPC_HAVE_PMU_SUPPORT + select SYS_SUPPORTS_HUGETLBFS config PPC_BOOK3E_64 bool "Embedded processors" @@ -173,6 +174,7 @@ config BOOKE config FSL_BOOKE bool depends on (E200 || E500) && PPC32 + select SYS_SUPPORTS_HUGETLBFS if PHYS_64BIT default y # this is for common code between PPC32 & PPC64 FSL BOOKE @@ -296,7 +298,7 @@ config PPC_BOOK3E_MMU config PPC_MM_SLICES bool - default y if HUGETLB_PAGE || (PPC_STD_MMU_64 && PPC_64K_PAGES) + default y if (PPC64 && HUGETLB_PAGE) || (PPC_STD_MMU_64 && PPC_64K_PAGES) default n config VIRT_CPU_ACCOUNTING From 14b9247019432fc25e606b78262eb16a4a33b8ed Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 8 Jul 2011 11:12:42 +0000 Subject: [PATCH 0387/1596] powerpc/mpic: Add support for discontiguous cores There is one place in the MPIC driver that assumes that the cores are numbered from 0 to n-1. However, this is not true if the CPUs are not numbered sequentially. This can happen on a eight-core SOC where cores two and three are removed in the device tree. So instead of blindly looping, we iterate over the discovered CPUs and use the SMP ID as the index. This means that we no longer ask the MPIC how many CPUs there are, so we also delete mpic->num_cpus. We also catch if the number of CPUs in the SOC exceeds the number that the MPIC supports. This should never happen, of course, but it's good to be sure. Signed-off-by: Timur Tabi Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/mpic.h | 2 -- arch/powerpc/sysdev/mpic.c | 24 +++++++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index df18989e78d4..e6fae49e0b74 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -273,8 +273,6 @@ struct mpic unsigned int irq_count; /* Number of sources */ unsigned int num_sources; - /* Number of CPUs */ - unsigned int num_cpus; /* default senses array */ unsigned char *senses; unsigned int senses_count; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index d5d3ff3d757e..9678081dc4e2 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1285,13 +1285,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | MPIC_GREG_GCONF_MCK); - /* Read feature register, calculate num CPUs and, for non-ISU - * MPICs, num sources as well. On ISU MPICs, sources are counted - * as ISUs are added + /* + * Read feature register. For non-ISU MPICs, num sources as well. On + * ISU MPICs, sources are counted as ISUs are added */ greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); - mpic->num_cpus = ((greg_feature & MPIC_GREG_FEATURE_LAST_CPU_MASK) - >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; if (isu_size == 0) { if (flags & MPIC_BROKEN_FRR_NIRQS) mpic->num_sources = mpic->irq_count; @@ -1301,10 +1299,18 @@ struct mpic * __init mpic_alloc(struct device_node *node, >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; } + /* + * The MPIC driver will crash if there are more cores than we + * can initialize, so we may as well catch that problem here. + */ + BUG_ON(num_possible_cpus() > MPIC_MAX_CPUS); + /* Map the per-CPU registers */ - for (i = 0; i < mpic->num_cpus; i++) { - mpic_map(mpic, node, paddr, &mpic->cpuregs[i], - MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), + for_each_possible_cpu(i) { + unsigned int cpu = get_hard_smp_processor_id(i); + + mpic_map(mpic, node, paddr, &mpic->cpuregs[cpu], + MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), 0x1000); } @@ -1343,7 +1349,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, } printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," " max %d CPUs\n", - name, vers, (unsigned long long)paddr, mpic->num_cpus); + name, vers, (unsigned long long)paddr, num_possible_cpus()); printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, mpic->isu_shift, mpic->isu_mask); From 7392769365f32c82340f184f93408b12dc3da4dc Mon Sep 17 00:00:00 2001 From: Matthew McClintock Date: Tue, 19 Jul 2011 06:22:44 +0000 Subject: [PATCH 0388/1596] powerpc: Fix build dependencies for epapr.c which needs libfdt.h Currently, the build can (very rarely) fail to build because libfdt.h has not been created or is in the process of being copied. Signed-off-by: Matthew McClintock Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index c26200b40a47..ac6705e75711 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -58,7 +58,7 @@ $(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o prpmc2800.o): \ libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c libfdtheader := fdt.h libfdt.h libfdt_internal.h -$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o): \ +$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o): \ $(addprefix $(obj)/,$(libfdtheader)) src-wlib := string.S crt0.S crtsavres.S stdio.c main.c \ From 6c493685f1b209dd4ae41eb52c818cf12da20def Mon Sep 17 00:00:00 2001 From: Jim Keniston Date: Mon, 25 Jul 2011 07:54:50 +0000 Subject: [PATCH 0389/1596] powerpc/nvram: Add compression to fit more oops output into NVRAM Capture more than twice as much text from the printk buffer, and compress it to fit it in the lnx,oops-log NVRAM partition. You can view the compressed text using the new (as of July 20) --unzip option of the nvram command in the powerpc-utils package. [BenH: Added select of ZLIB_DEFLATE] Signed-off-by: Jim Keniston Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/rtas.h | 6 +- arch/powerpc/platforms/pseries/Kconfig | 1 + arch/powerpc/platforms/pseries/nvram.c | 171 ++++++++++++++++++++++++- 3 files changed, 169 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 58625d1e7802..41f69ae79d4e 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -249,10 +249,12 @@ extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); #define ERR_FLAG_ALREADY_LOGGED 0x0 #define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */ #define ERR_TYPE_RTAS_LOG 0x2 /* from rtas event-scan */ -#define ERR_TYPE_KERNEL_PANIC 0x4 /* from panic() */ +#define ERR_TYPE_KERNEL_PANIC 0x4 /* from die()/panic() */ +#define ERR_TYPE_KERNEL_PANIC_GZ 0x8 /* ditto, compressed */ /* All the types and not flags */ -#define ERR_TYPE_MASK (ERR_TYPE_RTAS_LOG | ERR_TYPE_KERNEL_PANIC) +#define ERR_TYPE_MASK \ + (ERR_TYPE_RTAS_LOG | ERR_TYPE_KERNEL_PANIC | ERR_TYPE_KERNEL_PANIC_GZ) #define RTAS_DEBUG KERN_DEBUG "RTAS: " diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 05cf4769b88c..c81f6bb9c10f 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -15,6 +15,7 @@ config PPC_PSERIES select PPC_UDBG_16550 select PPC_NATIVE select PPC_PCI_CHOICE if EXPERT + select ZLIB_DEFLATE default y config PPC_SPLPAR diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 00cc3a094885..a76b22844d18 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -78,8 +80,41 @@ static struct kmsg_dumper nvram_kmsg_dumper = { #define NVRAM_RTAS_READ_TIMEOUT 5 /* seconds */ static unsigned long last_unread_rtas_event; /* timestamp */ -/* We preallocate oops_buf during init to avoid kmalloc during oops/panic. */ -static char *oops_buf; +/* + * For capturing and compressing an oops or panic report... + + * big_oops_buf[] holds the uncompressed text we're capturing. + * + * oops_buf[] holds the compressed text, preceded by a prefix. + * The prefix is just a u16 holding the length of the compressed* text. + * (*Or uncompressed, if compression fails.) oops_buf[] gets written + * to NVRAM. + * + * oops_len points to the prefix. oops_data points to the compressed text. + * + * +- oops_buf + * | +- oops_data + * v v + * +------------+-----------------------------------------------+ + * | length | text | + * | (2 bytes) | (oops_data_sz bytes) | + * +------------+-----------------------------------------------+ + * ^ + * +- oops_len + * + * We preallocate these buffers during init to avoid kmalloc during oops/panic. + */ +static size_t big_oops_buf_sz; +static char *big_oops_buf, *oops_buf; +static u16 *oops_len; +static char *oops_data; +static size_t oops_data_sz; + +/* Compression parameters */ +#define COMPR_LEVEL 6 +#define WINDOW_BITS 12 +#define MEM_LEVEL 4 +static struct z_stream_s stream; static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) { @@ -387,11 +422,44 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists) sizeof(rtas_log_partition)); } oops_buf = kmalloc(oops_log_partition.size, GFP_KERNEL); + if (!oops_buf) { + pr_err("nvram: No memory for %s partition\n", + oops_log_partition.name); + return; + } + oops_len = (u16*) oops_buf; + oops_data = oops_buf + sizeof(u16); + oops_data_sz = oops_log_partition.size - sizeof(u16); + + /* + * Figure compression (preceded by elimination of each line's + * severity prefix) will reduce the oops/panic report to at most + * 45% of its original size. + */ + big_oops_buf_sz = (oops_data_sz * 100) / 45; + big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); + if (big_oops_buf) { + stream.workspace = kmalloc(zlib_deflate_workspacesize( + WINDOW_BITS, MEM_LEVEL), GFP_KERNEL); + if (!stream.workspace) { + pr_err("nvram: No memory for compression workspace; " + "skipping compression of %s partition data\n", + oops_log_partition.name); + kfree(big_oops_buf); + big_oops_buf = NULL; + } + } else { + pr_err("No memory for uncompressed %s data; " + "skipping compression\n", oops_log_partition.name); + stream.workspace = NULL; + } + rc = kmsg_dump_register(&nvram_kmsg_dumper); if (rc != 0) { pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc); kfree(oops_buf); - return; + kfree(big_oops_buf); + kfree(stream.workspace); } } @@ -473,7 +541,83 @@ static int clobbering_unread_rtas_event(void) NVRAM_RTAS_READ_TIMEOUT); } -/* our kmsg_dump callback */ +/* Squeeze out each line's severity prefix. */ +static size_t elide_severities(char *buf, size_t len) +{ + char *in, *out, *buf_end = buf + len; + /* Assume a at the very beginning marks the start of a line. */ + int newline = 1; + + in = out = buf; + while (in < buf_end) { + if (newline && in+3 <= buf_end && + *in == '<' && isdigit(in[1]) && in[2] == '>') { + in += 3; + newline = 0; + } else { + newline = (*in == '\n'); + *out++ = *in++; + } + } + return out - buf; +} + +/* Derived from logfs_compress() */ +static int nvram_compress(const void *in, void *out, size_t inlen, + size_t outlen) +{ + int err, ret; + + ret = -EIO; + err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, + MEM_LEVEL, Z_DEFAULT_STRATEGY); + if (err != Z_OK) + goto error; + + stream.next_in = in; + stream.avail_in = inlen; + stream.total_in = 0; + stream.next_out = out; + stream.avail_out = outlen; + stream.total_out = 0; + + err = zlib_deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) + goto error; + + err = zlib_deflateEnd(&stream); + if (err != Z_OK) + goto error; + + if (stream.total_out >= stream.total_in) + goto error; + + ret = stream.total_out; +error: + return ret; +} + +/* Compress the text from big_oops_buf into oops_buf. */ +static int zip_oops(size_t text_len) +{ + int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, + oops_data_sz); + if (zipped_len < 0) { + pr_err("nvram: compression failed; returned %d\n", zipped_len); + pr_err("nvram: logging uncompressed oops/panic report\n"); + return -1; + } + *oops_len = (u16) zipped_len; + return 0; +} + +/* + * This is our kmsg_dump callback, called after an oops or panic report + * has been written to the printk buffer. We want to capture as much + * of the printk buffer as possible. First, capture as much as we can + * that we think will compress sufficiently to fit in the lnx,oops-log + * partition. If that's too much, go back and capture uncompressed text. + */ static void oops_to_nvram(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason, const char *old_msgs, unsigned long old_len, @@ -482,6 +626,8 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, static unsigned int oops_count = 0; static bool panicking = false; size_t text_len; + unsigned int err_type = ERR_TYPE_KERNEL_PANIC_GZ; + int rc = -1; switch (reason) { case KMSG_DUMP_RESTART: @@ -509,8 +655,19 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, if (clobbering_unread_rtas_event()) return; - text_len = capture_last_msgs(old_msgs, old_len, new_msgs, new_len, - oops_buf, oops_log_partition.size); + if (big_oops_buf) { + text_len = capture_last_msgs(old_msgs, old_len, + new_msgs, new_len, big_oops_buf, big_oops_buf_sz); + text_len = elide_severities(big_oops_buf, text_len); + rc = zip_oops(text_len); + } + if (rc != 0) { + text_len = capture_last_msgs(old_msgs, old_len, + new_msgs, new_len, oops_data, oops_data_sz); + err_type = ERR_TYPE_KERNEL_PANIC; + *oops_len = (u16) text_len; + } + (void) nvram_write_os_partition(&oops_log_partition, oops_buf, - (int) text_len, ERR_TYPE_KERNEL_PANIC, ++oops_count); + (int) (sizeof(*oops_len) + *oops_len), err_type, ++oops_count); } From 6dece0eb69b2a28e18d104bc5d707f1cb673f5e0 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 25 Jul 2011 11:29:33 +0000 Subject: [PATCH 0390/1596] powerpc/32: Pass device tree address as u64 to machine_init u64 is used rather than phys_addr_t to keep things simple, as this is called from assembly code. Update callers to pass a 64-bit address in r3/r4. Other unused register assignments that were once parameters to machine_init are dropped. For FSL BookE, look up the physical address of the device tree from the effective address passed in r3 by the loader. This is required for situations where memory does not start at zero (due to AMP or IOMMU-less virtualization), and thus the IMA doesn't start at zero, and thus the device tree effective address does not equal the physical address. Signed-off-by: Scott Wood Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/head_32.S | 7 ++--- arch/powerpc/kernel/head_40x.S | 15 ++-------- arch/powerpc/kernel/head_44x.S | 16 ++--------- arch/powerpc/kernel/head_8xx.S | 13 ++------- arch/powerpc/kernel/head_fsl_booke.S | 42 +++++++++++++++++----------- arch/powerpc/kernel/setup_32.c | 2 +- 6 files changed, 39 insertions(+), 56 deletions(-) diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index ba250d505e07..0654dba2c1f1 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -139,8 +139,7 @@ __start: trap #endif /* CONFIG_PPC_PMAC */ -1: mr r31,r3 /* save parameters */ - mr r30,r4 +1: mr r31,r3 /* save device tree ptr */ li r24,0 /* cpu # */ /* @@ -964,8 +963,8 @@ start_here: * Do early platform-specific initialization, * and set up the MMU. */ - mr r3,r31 - mr r4,r30 + li r3,0 + mr r4,r31 bl machine_init bl __save_cpu_setup bl MMU_init diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index a91626d87fc9..872a6af83bad 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -58,13 +58,7 @@ _ENTRY(_stext); _ENTRY(_start); - /* Save parameters we are passed. - */ - mr r31,r3 - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 + mr r31,r3 /* save device tree ptr */ /* We have to turn on the MMU right away so we get cache modes * set correctly. @@ -849,11 +843,8 @@ start_here: /* * Decide what sort of machine this is and initialize the MMU. */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 + li r3,0 + mr r4,r31 bl machine_init bl MMU_init diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index f8e971ba94f5..b725dab0f88a 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -61,14 +61,7 @@ _ENTRY(_start); * of abatron_pteptrs */ nop -/* - * Save parameters we are passed - */ - mr r31,r3 - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 + mr r31,r3 /* save device tree ptr */ li r24,0 /* CPU number */ bl init_cpu_state @@ -120,11 +113,8 @@ _ENTRY(_start); /* * Decide what sort of machine this is and initialize the MMU. */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 + li r3,0 + mr r4,r31 bl machine_init bl MMU_init diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 1cbf64e6b416..b68cb173ba2c 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -76,11 +76,7 @@ _ENTRY(_start); */ .globl __start __start: - mr r31,r3 /* save parameters */ - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 + mr r31,r3 /* save device tree ptr */ /* We have to turn on the MMU right away so we get cache modes * set correctly. @@ -723,11 +719,8 @@ start_here: /* * Decide what sort of machine this is and initialize the MMU. */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 + li r3,0 + mr r4,r31 bl machine_init bl MMU_init diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 4ea9bfbf67e9..e1c699f3b7a7 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -63,17 +63,30 @@ _ENTRY(_start); * of abatron_pteptrs */ nop -/* - * Save parameters we are passed - */ - mr r31,r3 - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 - li r25,0 /* phys kernel start (low) */ - li r24,0 /* CPU number */ - li r23,0 /* phys kernel start (high) */ + + /* Translate device tree address to physical, save in r30/r31 */ + mfmsr r16 + mfspr r17,SPRN_PID + rlwinm r17,r17,16,0x3fff0000 /* turn PID into MAS6[SPID] */ + rlwimi r17,r16,28,0x00000001 /* turn MSR[DS] into MAS6[SAS] */ + mtspr SPRN_MAS6,r17 + + tlbsx 0,r3 /* must succeed */ + + mfspr r16,SPRN_MAS1 + mfspr r20,SPRN_MAS3 + rlwinm r17,r16,25,0x1f /* r17 = log2(page size) */ + li r18,1024 + slw r18,r18,r17 /* r18 = page size */ + addi r18,r18,-1 + and r19,r3,r18 /* r19 = page offset */ + andc r31,r20,r18 /* r3 = page base */ + or r31,r31,r19 /* r3 = devtree phys addr */ + mfspr r30,SPRN_MAS7 + + li r25,0 /* phys kernel start (low) */ + li r24,0 /* CPU number */ + li r23,0 /* phys kernel start (high) */ /* We try to not make any assumptions about how the boot loader * setup or used the TLBs. We invalidate all mappings from the @@ -198,11 +211,8 @@ _ENTRY(__early_start) /* * Decide what sort of machine this is and initialize the MMU. */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 + mr r3,r30 + mr r4,r31 bl machine_init bl MMU_init diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 209135af0a40..c1ce86357ecb 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -117,7 +117,7 @@ notrace unsigned long __init early_init(unsigned long dt_ptr) * This is called very early on the boot process, after a minimal * MMU environment has been set up but before MMU_init is called. */ -notrace void __init machine_init(unsigned long dt_ptr) +notrace void __init machine_init(u64 dt_ptr) { lockdep_init(); From 7a19081fc2658157a1b84e6f3288450c33d98569 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 8 Aug 2011 01:18:00 +0000 Subject: [PATCH 0391/1596] pseries/iommu: Add missing kfree At this point, window has not been stored anywhere, so it has to be freed before leaving the function. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @exists@ local idexpression x; statement S,S1; expression E; identifier fl; expression *ptr != NULL; @@ x = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...kfree(x)...+> } when any when != true x == NULL x->fl ...> ( if (x == NULL) S1 | if (...) { ... when != x when forall ( return \(0\|<+...x...+>\|ptr\); | * return ...; ) } ) // Signed-off-by: Julia Lawall Acked-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/iommu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 9f121a37eb51..5905a3b9f7e6 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -939,14 +939,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) if (ret) { dev_info(&dev->dev, "failed to map direct window for %s: %d\n", dn->full_name, ret); - goto out_clear_window; + goto out_free_window; } ret = prom_add_property(pdn, win64); if (ret) { dev_err(&dev->dev, "unable to add dma window property for %s: %d", pdn->full_name, ret); - goto out_clear_window; + goto out_free_window; } window->device = pdn; @@ -958,6 +958,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) dma_addr = of_read_number(&create.addr_hi, 2); goto out_unlock; +out_free_window: + kfree(window); + out_clear_window: remove_ddw(pdn); From 2fa3d9e5c699ff49e96199eeb9bea4508e7f5dac Mon Sep 17 00:00:00 2001 From: Jimi Xenidis Date: Mon, 8 Aug 2011 11:33:16 +0000 Subject: [PATCH 0392/1596] powerpc/wsp: Fix Wire Speed Processor platform configs Some config selections were applied to the platform (reference board) when they actuall apply to the chip. Signed-off-by: Jimi Xenidis Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/wsp/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig index c3c48eb62cc1..d051581e9ebf 100644 --- a/arch/powerpc/platforms/wsp/Kconfig +++ b/arch/powerpc/platforms/wsp/Kconfig @@ -1,5 +1,9 @@ config PPC_WSP bool + select PPC_A2 + select PPC_SCOM + select PPC_XICS + select PPC_ICP_NATIVE default n menu "WSP platform selection" @@ -7,13 +11,9 @@ menu "WSP platform selection" config PPC_PSR2 bool "PSR-2 platform" - select PPC_A2 select GENERIC_TBSYNC - select PPC_SCOM select EPAPR_BOOT select PPC_WSP - select PPC_XICS - select PPC_ICP_NATIVE default y endmenu From f352c7251255effe6c2326190f1378adbd142aa3 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 8 Aug 2011 12:30:54 +0000 Subject: [PATCH 0393/1596] powerpc/wsp: Add PCIe Root support to PowerEN/WSP Based on a patch by Benjamin Herrenschmidt Modernized and slightly modified to not record erros into the nvram log since we do not have that device driver just yet. Jimi Xenidis Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/wsp/Kconfig | 3 + arch/powerpc/platforms/wsp/Makefile | 1 + arch/powerpc/platforms/wsp/psr2.c | 4 + arch/powerpc/platforms/wsp/wsp.h | 3 + arch/powerpc/platforms/wsp/wsp_pci.c | 1133 ++++++++++++++++++++++++++ arch/powerpc/platforms/wsp/wsp_pci.h | 268 ++++++ 6 files changed, 1412 insertions(+) create mode 100644 arch/powerpc/platforms/wsp/wsp_pci.c create mode 100644 arch/powerpc/platforms/wsp/wsp_pci.h diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig index d051581e9ebf..f4fb837873fb 100644 --- a/arch/powerpc/platforms/wsp/Kconfig +++ b/arch/powerpc/platforms/wsp/Kconfig @@ -4,6 +4,9 @@ config PPC_WSP select PPC_SCOM select PPC_XICS select PPC_ICP_NATIVE + select PCI + select PPC_IO_WORKAROUNDS if PCI + select PPC_INDIRECT_PIO if PCI default n menu "WSP platform selection" diff --git a/arch/powerpc/platforms/wsp/Makefile b/arch/powerpc/platforms/wsp/Makefile index 095be73d6cd4..84519f8d8945 100644 --- a/arch/powerpc/platforms/wsp/Makefile +++ b/arch/powerpc/platforms/wsp/Makefile @@ -4,3 +4,4 @@ obj-y += setup.o ics.o obj-$(CONFIG_PPC_PSR2) += psr2.o opb_pic.o obj-$(CONFIG_PPC_WSP) += scom_wsp.o obj-$(CONFIG_SMP) += smp.o scom_smp.o +obj-$(CONFIG_PCI) += wsp_pci.o diff --git a/arch/powerpc/platforms/wsp/psr2.c b/arch/powerpc/platforms/wsp/psr2.c index 40f28916ff6c..166f2e4b4bee 100644 --- a/arch/powerpc/platforms/wsp/psr2.c +++ b/arch/powerpc/platforms/wsp/psr2.c @@ -63,6 +63,10 @@ static void __init psr2_setup_arch(void) #ifdef CONFIG_SMP a2_setup_smp(); #endif +#ifdef CONFIG_PCI + wsp_setup_pci(); +#endif + } static int __init psr2_probe(void) diff --git a/arch/powerpc/platforms/wsp/wsp.h b/arch/powerpc/platforms/wsp/wsp.h index 7c3e087fd2f2..33479818f62a 100644 --- a/arch/powerpc/platforms/wsp/wsp.h +++ b/arch/powerpc/platforms/wsp/wsp.h @@ -3,6 +3,9 @@ #include +/* Devtree compatible strings for major devices */ +#define PCIE_COMPATIBLE "ibm,wsp-pciex" + extern void wsp_setup_pci(void); extern void scom_init_wsp(void); diff --git a/arch/powerpc/platforms/wsp/wsp_pci.c b/arch/powerpc/platforms/wsp/wsp_pci.c new file mode 100644 index 000000000000..e0262cd0e2d3 --- /dev/null +++ b/arch/powerpc/platforms/wsp/wsp_pci.c @@ -0,0 +1,1133 @@ +/* + * Copyright 2010 Ben Herrenschmidt, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wsp.h" +#include "wsp_pci.h" +#include "msi.h" + + +/* Max number of TVTs for one table. Only 32-bit tables can use + * multiple TVTs and so the max currently supported is thus 8 + * since only 2G of DMA space is supported + */ +#define MAX_TABLE_TVT_COUNT 8 + +struct wsp_dma_table { + struct list_head link; + struct iommu_table table; + struct wsp_phb *phb; + struct page *tces[MAX_TABLE_TVT_COUNT]; +}; + +/* We support DMA regions from 0...2G in 32bit space (no support for + * 64-bit DMA just yet). Each device gets a separate TCE table (TVT + * entry) with validation enabled (though not supported by SimiCS + * just yet). + * + * To simplify things, we divide this 2G space into N regions based + * on the constant below which could be turned into a tunable eventually + * + * We then assign dynamically those regions to devices as they show up. + * + * We use a bitmap as an allocator for these. + * + * Tables are allocated/created dynamically as devices are discovered, + * multiple TVT entries are used if needed + * + * When 64-bit DMA support is added we should simply use a separate set + * of larger regions (the HW supports 64 TVT entries). We can + * additionally create a bypass region in 64-bit space for performances + * though that would have a cost in term of security. + * + * If you set NUM_DMA32_REGIONS to 1, then a single table is shared + * for all devices and bus/dev/fn validation is disabled + * + * Note that a DMA32 region cannot be smaller than 256M so the max + * supported here for now is 8. We don't yet support sharing regions + * between multiple devices so the max number of devices supported + * is MAX_TABLE_TVT_COUNT. + */ +#define NUM_DMA32_REGIONS 1 + +struct wsp_phb { + struct pci_controller *hose; + + /* Lock controlling access to the list of dma tables. + * It does -not- protect against dma_* operations on + * those tables, those should be stopped before an entry + * is removed from the list. + * + * The lock is also used for error handling operations + */ + spinlock_t lock; + struct list_head dma_tables; + unsigned long dma32_map; + unsigned long dma32_base; + unsigned int dma32_num_regions; + unsigned long dma32_region_size; + + /* Debugfs stuff */ + struct dentry *ddir; + + struct list_head all; +}; +static LIST_HEAD(wsp_phbs); + +//#define cfg_debug(fmt...) pr_debug(fmt) +#define cfg_debug(fmt...) + + +static int wsp_pcie_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose; + int suboff; + u64 addr; + + hose = pci_bus_to_host(bus); + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset >= 0x1000) + return PCIBIOS_BAD_REGISTER_NUMBER; + addr = PCIE_REG_CA_ENABLE | + ((u64)bus->number) << PCIE_REG_CA_BUS_SHIFT | + ((u64)devfn) << PCIE_REG_CA_FUNC_SHIFT | + ((u64)offset & ~3) << PCIE_REG_CA_REG_SHIFT; + suboff = offset & 3; + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + + switch (len) { + case 1: + addr |= (0x8ul >> suboff) << PCIE_REG_CA_BE_SHIFT; + out_be64(hose->cfg_data + PCIE_REG_CONFIG_ADDRESS, addr); + *val = (in_le32(hose->cfg_data + PCIE_REG_CONFIG_DATA) + >> (suboff << 3)) & 0xff; + cfg_debug("read 1 %02x:%02x:%02x + %02x/%x addr=0x%llx val=%02x\n", + bus->number, devfn >> 3, devfn & 7, + offset, suboff, addr, *val); + break; + case 2: + addr |= (0xcul >> suboff) << PCIE_REG_CA_BE_SHIFT; + out_be64(hose->cfg_data + PCIE_REG_CONFIG_ADDRESS, addr); + *val = (in_le32(hose->cfg_data + PCIE_REG_CONFIG_DATA) + >> (suboff << 3)) & 0xffff; + cfg_debug("read 2 %02x:%02x:%02x + %02x/%x addr=0x%llx val=%04x\n", + bus->number, devfn >> 3, devfn & 7, + offset, suboff, addr, *val); + break; + default: + addr |= 0xful << PCIE_REG_CA_BE_SHIFT; + out_be64(hose->cfg_data + PCIE_REG_CONFIG_ADDRESS, addr); + *val = in_le32(hose->cfg_data + PCIE_REG_CONFIG_DATA); + cfg_debug("read 4 %02x:%02x:%02x + %02x/%x addr=0x%llx val=%08x\n", + bus->number, devfn >> 3, devfn & 7, + offset, suboff, addr, *val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int wsp_pcie_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 val) +{ + struct pci_controller *hose; + int suboff; + u64 addr; + + hose = pci_bus_to_host(bus); + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset >= 0x1000) + return PCIBIOS_BAD_REGISTER_NUMBER; + addr = PCIE_REG_CA_ENABLE | + ((u64)bus->number) << PCIE_REG_CA_BUS_SHIFT | + ((u64)devfn) << PCIE_REG_CA_FUNC_SHIFT | + ((u64)offset & ~3) << PCIE_REG_CA_REG_SHIFT; + suboff = offset & 3; + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + addr |= (0x8ul >> suboff) << PCIE_REG_CA_BE_SHIFT; + val <<= suboff << 3; + out_be64(hose->cfg_data + PCIE_REG_CONFIG_ADDRESS, addr); + out_le32(hose->cfg_data + PCIE_REG_CONFIG_DATA, val); + cfg_debug("write 1 %02x:%02x:%02x + %02x/%x addr=0x%llx val=%02x\n", + bus->number, devfn >> 3, devfn & 7, + offset, suboff, addr, val); + break; + case 2: + addr |= (0xcul >> suboff) << PCIE_REG_CA_BE_SHIFT; + val <<= suboff << 3; + out_be64(hose->cfg_data + PCIE_REG_CONFIG_ADDRESS, addr); + out_le32(hose->cfg_data + PCIE_REG_CONFIG_DATA, val); + cfg_debug("write 2 %02x:%02x:%02x + %02x/%x addr=0x%llx val=%04x\n", + bus->number, devfn >> 3, devfn & 7, + offset, suboff, addr, val); + break; + default: + addr |= 0xful << PCIE_REG_CA_BE_SHIFT; + out_be64(hose->cfg_data + PCIE_REG_CONFIG_ADDRESS, addr); + out_le32(hose->cfg_data + PCIE_REG_CONFIG_DATA, val); + cfg_debug("write 4 %02x:%02x:%02x + %02x/%x addr=0x%llx val=%08x\n", + bus->number, devfn >> 3, devfn & 7, + offset, suboff, addr, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops wsp_pcie_pci_ops = +{ + .read = wsp_pcie_read_config, + .write = wsp_pcie_write_config, +}; + +#define TCE_SHIFT 12 +#define TCE_PAGE_SIZE (1 << TCE_SHIFT) +#define TCE_PCI_WRITE 0x2 /* write from PCI allowed */ +#define TCE_PCI_READ 0x1 /* read from PCI allowed */ +#define TCE_RPN_MASK 0x3fffffffffful /* 42-bit RPN (4K pages) */ +#define TCE_RPN_SHIFT 12 + +//#define dma_debug(fmt...) pr_debug(fmt) +#define dma_debug(fmt...) + +static int tce_build_wsp(struct iommu_table *tbl, long index, long npages, + unsigned long uaddr, enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + struct wsp_dma_table *ptbl = container_of(tbl, + struct wsp_dma_table, + table); + u64 proto_tce; + u64 *tcep; + u64 rpn; + + proto_tce = TCE_PCI_READ; +#ifdef CONFIG_WSP_DD1_WORKAROUND_DD1_TCE_BUGS + proto_tce |= TCE_PCI_WRITE; +#else + if (direction != DMA_TO_DEVICE) + proto_tce |= TCE_PCI_WRITE; +#endif + + /* XXX Make this faster by factoring out the page address for + * within a TCE table + */ + while (npages--) { + /* We don't use it->base as the table can be scattered */ + tcep = (u64 *)page_address(ptbl->tces[index >> 16]); + tcep += (index & 0xffff); + + /* can't move this out since we might cross LMB boundary */ + rpn = __pa(uaddr) >> TCE_SHIFT; + *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; + + dma_debug("[DMA] TCE %p set to 0x%016llx (dma addr: 0x%lx)\n", + tcep, *tcep, (tbl->it_offset + index) << IOMMU_PAGE_SHIFT); + + uaddr += TCE_PAGE_SIZE; + index++; + } + return 0; +} + +static void tce_free_wsp(struct iommu_table *tbl, long index, long npages) +{ + struct wsp_dma_table *ptbl = container_of(tbl, + struct wsp_dma_table, + table); +#ifndef CONFIG_WSP_DD1_WORKAROUND_DD1_TCE_BUGS + struct pci_controller *hose = ptbl->phb->hose; +#endif + u64 *tcep; + + /* XXX Make this faster by factoring out the page address for + * within a TCE table. Also use line-kill option to kill multiple + * TCEs at once + */ + while (npages--) { + /* We don't use it->base as the table can be scattered */ + tcep = (u64 *)page_address(ptbl->tces[index >> 16]); + tcep += (index & 0xffff); + dma_debug("[DMA] TCE %p cleared\n", tcep); + *tcep = 0; +#ifndef CONFIG_WSP_DD1_WORKAROUND_DD1_TCE_BUGS + /* Don't write there since it would pollute other MMIO accesses */ + out_be64(hose->cfg_data + PCIE_REG_TCE_KILL, + PCIE_REG_TCEKILL_SINGLE | PCIE_REG_TCEKILL_PS_4K | + (__pa(tcep) & PCIE_REG_TCEKILL_ADDR_MASK)); +#endif + index++; + } +} + +static struct wsp_dma_table *wsp_pci_create_dma32_table(struct wsp_phb *phb, + unsigned int region, + struct pci_dev *validate) +{ + struct pci_controller *hose = phb->hose; + unsigned long size = phb->dma32_region_size; + unsigned long addr = phb->dma32_region_size * region + phb->dma32_base; + struct wsp_dma_table *tbl; + int tvts_per_table, i, tvt, nid; + unsigned long flags; + + nid = of_node_to_nid(phb->hose->dn); + + /* Calculate how many TVTs are needed */ + tvts_per_table = size / 0x10000000; + if (tvts_per_table == 0) + tvts_per_table = 1; + + /* Calculate the base TVT index. We know all tables have the same + * size so we just do a simple multiply here + */ + tvt = region * tvts_per_table; + + pr_debug(" Region : %d\n", region); + pr_debug(" DMA range : 0x%08lx..0x%08lx\n", addr, addr + size - 1); + pr_debug(" Number of TVTs : %d\n", tvts_per_table); + pr_debug(" Base TVT : %d\n", tvt); + pr_debug(" Node : %d\n", nid); + + tbl = kzalloc_node(sizeof(struct wsp_dma_table), GFP_KERNEL, nid); + if (!tbl) + return ERR_PTR(-ENOMEM); + tbl->phb = phb; + + /* Create as many TVTs as needed, each represents 256M at most */ + for (i = 0; i < tvts_per_table; i++) { + u64 tvt_data1, tvt_data0; + + /* Allocate table. We use a 4K TCE size for now always so + * one table is always 8 * (258M / 4K) == 512K + */ + tbl->tces[i] = alloc_pages_node(nid, GFP_KERNEL, get_order(0x80000)); + if (tbl->tces[i] == NULL) + goto fail; + memset(page_address(tbl->tces[i]), 0, 0x80000); + + pr_debug(" TCE table %d at : %p\n", i, page_address(tbl->tces[i])); + + /* Table size. We currently set it to be the whole 256M region */ + tvt_data0 = 2ull << IODA_TVT0_TCE_TABLE_SIZE_SHIFT; + /* IO page size set to 4K */ + tvt_data1 = 1ull << IODA_TVT1_IO_PAGE_SIZE_SHIFT; + /* Shift in the address */ + tvt_data0 |= __pa(page_address(tbl->tces[i])) << IODA_TVT0_TTA_SHIFT; + + /* Validation stuff. We only validate fully bus/dev/fn for now + * one day maybe we can group devices but that isn't the case + * at the moment + */ + if (validate) { + tvt_data0 |= IODA_TVT0_BUSNUM_VALID_MASK; + tvt_data0 |= validate->bus->number; + tvt_data1 |= IODA_TVT1_DEVNUM_VALID; + tvt_data1 |= ((u64)PCI_SLOT(validate->devfn)) + << IODA_TVT1_DEVNUM_VALUE_SHIFT; + tvt_data1 |= IODA_TVT1_FUNCNUM_VALID; + tvt_data1 |= ((u64)PCI_FUNC(validate->devfn)) + << IODA_TVT1_FUNCNUM_VALUE_SHIFT; + } + + /* XX PE number is always 0 for now */ + + /* Program the values using the PHB lock */ + spin_lock_irqsave(&phb->lock, flags); + out_be64(hose->cfg_data + PCIE_REG_IODA_ADDR, + (tvt + i) | PCIE_REG_IODA_AD_TBL_TVT); + out_be64(hose->cfg_data + PCIE_REG_IODA_DATA1, tvt_data1); + out_be64(hose->cfg_data + PCIE_REG_IODA_DATA0, tvt_data0); + spin_unlock_irqrestore(&phb->lock, flags); + } + + /* Init bits and pieces */ + tbl->table.it_blocksize = 16; + tbl->table.it_offset = addr >> IOMMU_PAGE_SHIFT; + tbl->table.it_size = size >> IOMMU_PAGE_SHIFT; + + /* + * It's already blank but we clear it anyway. + * Consider an aditiona interface that makes cleaing optional + */ + iommu_init_table(&tbl->table, nid); + + list_add(&tbl->link, &phb->dma_tables); + return tbl; + + fail: + pr_debug(" Failed to allocate a 256M TCE table !\n"); + for (i = 0; i < tvts_per_table; i++) + if (tbl->tces[i]) + __free_pages(tbl->tces[i], get_order(0x80000)); + kfree(tbl); + return ERR_PTR(-ENOMEM); +} + +static void __devinit wsp_pci_dma_dev_setup(struct pci_dev *pdev) +{ + struct dev_archdata *archdata = &pdev->dev.archdata; + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + struct wsp_phb *phb = hose->private_data; + struct wsp_dma_table *table = NULL; + unsigned long flags; + int i; + + /* Don't assign an iommu table to a bridge */ + if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + return; + + pr_debug("%s: Setting up DMA...\n", pci_name(pdev)); + + spin_lock_irqsave(&phb->lock, flags); + + /* If only one region, check if it already exist */ + if (phb->dma32_num_regions == 1) { + spin_unlock_irqrestore(&phb->lock, flags); + if (list_empty(&phb->dma_tables)) + table = wsp_pci_create_dma32_table(phb, 0, NULL); + else + table = list_first_entry(&phb->dma_tables, + struct wsp_dma_table, + link); + } else { + /* else find a free region */ + for (i = 0; i < phb->dma32_num_regions && !table; i++) { + if (__test_and_set_bit(i, &phb->dma32_map)) + continue; + spin_unlock_irqrestore(&phb->lock, flags); + table = wsp_pci_create_dma32_table(phb, i, pdev); + } + } + + /* Check if we got an error */ + if (IS_ERR(table)) { + pr_err("%s: Failed to create DMA table, err %ld !\n", + pci_name(pdev), PTR_ERR(table)); + return; + } + + /* Or a valid table */ + if (table) { + pr_info("%s: Setup iommu: 32-bit DMA region 0x%08lx..0x%08lx\n", + pci_name(pdev), + table->table.it_offset << IOMMU_PAGE_SHIFT, + (table->table.it_offset << IOMMU_PAGE_SHIFT) + + phb->dma32_region_size - 1); + archdata->dma_data.iommu_table_base = &table->table; + return; + } + + /* Or no room */ + spin_unlock_irqrestore(&phb->lock, flags); + pr_err("%s: Out of DMA space !\n", pci_name(pdev)); +} + +static void __init wsp_pcie_configure_hw(struct pci_controller *hose) +{ + u64 val; + int i; + +#define DUMP_REG(x) \ + pr_debug("%-30s : 0x%016llx\n", #x, in_be64(hose->cfg_data + x)) + +#ifdef CONFIG_WSP_DD1_WORKAROUND_BAD_PCIE_CLASS + /* WSP DD1 has a bogus class code by default in the PCI-E + * root complex's built-in P2P bridge */ + val = in_be64(hose->cfg_data + PCIE_REG_SYS_CFG1); + pr_debug("PCI-E SYS_CFG1 : 0x%llx\n", val); + out_be64(hose->cfg_data + PCIE_REG_SYS_CFG1, + (val & ~PCIE_REG_SYS_CFG1_CLASS_CODE) | (PCI_CLASS_BRIDGE_PCI << 8)); + pr_debug("PCI-E SYS_CFG1 : 0x%llx\n", in_be64(hose->cfg_data + PCIE_REG_SYS_CFG1)); +#endif /* CONFIG_WSP_DD1_WORKAROUND_BAD_PCIE_CLASS */ + +#ifdef CONFIG_WSP_DD1_WORKAROUND_DD1_TCE_BUGS + /* XXX Disable TCE caching, it doesn't work on DD1 */ + out_be64(hose->cfg_data + 0xe50, + in_be64(hose->cfg_data + 0xe50) | (3ull << 62)); + printk("PCI-E DEBUG CONTROL 5 = 0x%llx\n", in_be64(hose->cfg_data + 0xe50)); +#endif + + /* Configure M32A and IO. IO is hard wired to be 1M for now */ + out_be64(hose->cfg_data + PCIE_REG_IO_BASE_ADDR, hose->io_base_phys); + out_be64(hose->cfg_data + PCIE_REG_IO_BASE_MASK, + (~(hose->io_resource.end - hose->io_resource.start)) & + 0x3fffffff000ul); + out_be64(hose->cfg_data + PCIE_REG_IO_START_ADDR, 0 | 1); + + out_be64(hose->cfg_data + PCIE_REG_M32A_BASE_ADDR, + hose->mem_resources[0].start); + printk("Want to write to M32A_BASE_MASK : 0x%llx\n", + (~(hose->mem_resources[0].end - + hose->mem_resources[0].start)) & 0x3ffffff0000ul); + out_be64(hose->cfg_data + PCIE_REG_M32A_BASE_MASK, + (~(hose->mem_resources[0].end - + hose->mem_resources[0].start)) & 0x3ffffff0000ul); + out_be64(hose->cfg_data + PCIE_REG_M32A_START_ADDR, + (hose->mem_resources[0].start - hose->pci_mem_offset) | 1); + + /* Clear all TVT entries + * + * XX Might get TVT count from device-tree + */ + for (i = 0; i < IODA_TVT_COUNT; i++) { + out_be64(hose->cfg_data + PCIE_REG_IODA_ADDR, + PCIE_REG_IODA_AD_TBL_TVT | i); + out_be64(hose->cfg_data + PCIE_REG_IODA_DATA1, 0); + out_be64(hose->cfg_data + PCIE_REG_IODA_DATA0, 0); + } + + /* Kill the TCE cache */ + out_be64(hose->cfg_data + PCIE_REG_PHB_CONFIG, + in_be64(hose->cfg_data + PCIE_REG_PHB_CONFIG) | + PCIE_REG_PHBC_64B_TCE_EN); + + /* Enable 32 & 64-bit MSIs, IO space and M32A */ + val = PCIE_REG_PHBC_32BIT_MSI_EN | + PCIE_REG_PHBC_IO_EN | + PCIE_REG_PHBC_64BIT_MSI_EN | + PCIE_REG_PHBC_M32A_EN; + if (iommu_is_off) + val |= PCIE_REG_PHBC_DMA_XLATE_BYPASS; + pr_debug("Will write config: 0x%llx\n", val); + out_be64(hose->cfg_data + PCIE_REG_PHB_CONFIG, val); + + /* Enable error reporting */ + out_be64(hose->cfg_data + 0xe00, + in_be64(hose->cfg_data + 0xe00) | 0x0008000000000000ull); + + /* Mask an error that's generated when doing config space probe + * + * XXX Maybe we should only mask it around config space cycles... that or + * ignore it when we know we had a config space cycle recently ? + */ + out_be64(hose->cfg_data + PCIE_REG_DMA_ERR_STATUS_MASK, 0x8000000000000000ull); + out_be64(hose->cfg_data + PCIE_REG_DMA_ERR1_STATUS_MASK, 0x8000000000000000ull); + + /* Enable UTL errors, for now, all of them got to UTL irq 1 + * + * We similarily mask one UTL error caused apparently during normal + * probing. We also mask the link up error + */ + out_be64(hose->cfg_data + PCIE_UTL_SYS_BUS_AGENT_ERR_SEV, 0); + out_be64(hose->cfg_data + PCIE_UTL_RC_ERR_SEVERITY, 0); + out_be64(hose->cfg_data + PCIE_UTL_PCIE_PORT_ERROR_SEV, 0); + out_be64(hose->cfg_data + PCIE_UTL_SYS_BUS_AGENT_IRQ_EN, 0xffffffff00000000ull); + out_be64(hose->cfg_data + PCIE_UTL_PCIE_PORT_IRQ_EN, 0xff5fffff00000000ull); + out_be64(hose->cfg_data + PCIE_UTL_EP_ERR_IRQ_EN, 0xffffffff00000000ull); + + DUMP_REG(PCIE_REG_IO_BASE_ADDR); + DUMP_REG(PCIE_REG_IO_BASE_MASK); + DUMP_REG(PCIE_REG_IO_START_ADDR); + DUMP_REG(PCIE_REG_M32A_BASE_ADDR); + DUMP_REG(PCIE_REG_M32A_BASE_MASK); + DUMP_REG(PCIE_REG_M32A_START_ADDR); + DUMP_REG(PCIE_REG_M32B_BASE_ADDR); + DUMP_REG(PCIE_REG_M32B_BASE_MASK); + DUMP_REG(PCIE_REG_M32B_START_ADDR); + DUMP_REG(PCIE_REG_M64_BASE_ADDR); + DUMP_REG(PCIE_REG_M64_BASE_MASK); + DUMP_REG(PCIE_REG_M64_START_ADDR); + DUMP_REG(PCIE_REG_PHB_CONFIG); +} + +static void wsp_pci_wait_io_idle(struct wsp_phb *phb, unsigned long port) +{ + u64 val; + int i; + + for (i = 0; i < 10000; i++) { + val = in_be64(phb->hose->cfg_data + 0xe08); + if ((val & 0x1900000000000000ull) == 0x0100000000000000ull) + return; + udelay(1); + } + pr_warning("PCI IO timeout on domain %d port 0x%lx\n", + phb->hose->global_number, port); +} + +#define DEF_PCI_AC_RET_pio(name, ret, at, al, aa) \ +static ret wsp_pci_##name at \ +{ \ + struct iowa_bus *bus; \ + struct wsp_phb *phb; \ + unsigned long flags; \ + ret rval; \ + bus = iowa_pio_find_bus(aa); \ + WARN_ON(!bus); \ + phb = bus->private; \ + spin_lock_irqsave(&phb->lock, flags); \ + wsp_pci_wait_io_idle(phb, aa); \ + rval = __do_##name al; \ + spin_unlock_irqrestore(&phb->lock, flags); \ + return rval; \ +} + +#define DEF_PCI_AC_NORET_pio(name, at, al, aa) \ +static void wsp_pci_##name at \ +{ \ + struct iowa_bus *bus; \ + struct wsp_phb *phb; \ + unsigned long flags; \ + bus = iowa_pio_find_bus(aa); \ + WARN_ON(!bus); \ + phb = bus->private; \ + spin_lock_irqsave(&phb->lock, flags); \ + wsp_pci_wait_io_idle(phb, aa); \ + __do_##name al; \ + spin_unlock_irqrestore(&phb->lock, flags); \ +} + +#define DEF_PCI_AC_RET_mem(name, ret, at, al, aa) +#define DEF_PCI_AC_NORET_mem(name, at, al, aa) + +#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \ + DEF_PCI_AC_RET_##space(name, ret, at, al, aa) + +#define DEF_PCI_AC_NORET(name, at, al, space, aa) \ + DEF_PCI_AC_NORET_##space(name, at, al, aa) \ + + +#include + +#undef DEF_PCI_AC_RET +#undef DEF_PCI_AC_NORET + +static struct ppc_pci_io wsp_pci_iops = { + .inb = wsp_pci_inb, + .inw = wsp_pci_inw, + .inl = wsp_pci_inl, + .outb = wsp_pci_outb, + .outw = wsp_pci_outw, + .outl = wsp_pci_outl, + .insb = wsp_pci_insb, + .insw = wsp_pci_insw, + .insl = wsp_pci_insl, + .outsb = wsp_pci_outsb, + .outsw = wsp_pci_outsw, + .outsl = wsp_pci_outsl, +}; + +static int __init wsp_setup_one_phb(struct device_node *np) +{ + struct pci_controller *hose; + struct wsp_phb *phb; + + pr_info("PCI: Setting up PCIe host bridge 0x%s\n", np->full_name); + + phb = zalloc_maybe_bootmem(sizeof(struct wsp_phb), GFP_KERNEL); + if (!phb) + return -ENOMEM; + hose = pcibios_alloc_controller(np); + if (!hose) { + /* Can't really free the phb */ + return -ENOMEM; + } + hose->private_data = phb; + phb->hose = hose; + + INIT_LIST_HEAD(&phb->dma_tables); + spin_lock_init(&phb->lock); + + /* XXX Use bus-range property ? */ + hose->first_busno = 0; + hose->last_busno = 0xff; + + /* We use cfg_data as the address for the whole bridge MMIO space + */ + hose->cfg_data = of_iomap(hose->dn, 0); + + pr_debug("PCIe registers mapped at 0x%p\n", hose->cfg_data); + + /* Get the ranges of the device-tree */ + pci_process_bridge_OF_ranges(hose, np, 0); + + /* XXX Force re-assigning of everything for now */ + pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC | + PCI_ENABLE_PROC_DOMAINS); + pci_probe_only = 0; + + /* Calculate how the TCE space is divided */ + phb->dma32_base = 0; + phb->dma32_num_regions = NUM_DMA32_REGIONS; + if (phb->dma32_num_regions > MAX_TABLE_TVT_COUNT) { + pr_warning("IOMMU: Clamped to %d DMA32 regions\n", + MAX_TABLE_TVT_COUNT); + phb->dma32_num_regions = MAX_TABLE_TVT_COUNT; + } + phb->dma32_region_size = 0x80000000 / phb->dma32_num_regions; + + BUG_ON(!is_power_of_2(phb->dma32_region_size)); + + /* Setup config ops */ + hose->ops = &wsp_pcie_pci_ops; + + /* Configure the HW */ + wsp_pcie_configure_hw(hose); + + /* Instanciate IO workarounds */ + iowa_register_bus(hose, &wsp_pci_iops, NULL, phb); +#ifdef CONFIG_PCI_MSI + wsp_setup_phb_msi(hose); +#endif + + /* Add to global list */ + list_add(&phb->all, &wsp_phbs); + + return 0; +} + +void __init wsp_setup_pci(void) +{ + struct device_node *np; + int rc; + + /* Find host bridges */ + for_each_compatible_node(np, "pciex", PCIE_COMPATIBLE) { + rc = wsp_setup_one_phb(np); + if (rc) + pr_err("Failed to setup PCIe bridge %s, rc=%d\n", + np->full_name, rc); + } + + /* Establish device-tree linkage */ + pci_devs_phb_init(); + + /* Set DMA ops to use TCEs */ + if (iommu_is_off) { + pr_info("PCI-E: Disabled TCEs, using direct DMA\n"); + set_pci_dma_ops(&dma_direct_ops); + } else { + ppc_md.pci_dma_dev_setup = wsp_pci_dma_dev_setup; + ppc_md.tce_build = tce_build_wsp; + ppc_md.tce_free = tce_free_wsp; + set_pci_dma_ops(&dma_iommu_ops); + } +} + +#define err_debug(fmt...) pr_debug(fmt) +//#define err_debug(fmt...) + +static int __init wsp_pci_get_err_irq_no_dt(struct device_node *np) +{ + const u32 *prop; + int hw_irq; + + /* Ok, no interrupts property, let's try to find our child P2P */ + np = of_get_next_child(np, NULL); + if (np == NULL) + return 0; + + /* Grab it's interrupt map */ + prop = of_get_property(np, "interrupt-map", NULL); + if (prop == NULL) + return 0; + + /* Grab one of the interrupts in there, keep the low 4 bits */ + hw_irq = prop[5] & 0xf; + + /* 0..4 for PHB 0 and 5..9 for PHB 1 */ + if (hw_irq < 5) + hw_irq = 4; + else + hw_irq = 9; + hw_irq |= prop[5] & ~0xf; + + err_debug("PCI: Using 0x%x as error IRQ for %s\n", + hw_irq, np->parent->full_name); + return irq_create_mapping(NULL, hw_irq); +} + +static const struct { + u32 offset; + const char *name; +} wsp_pci_regs[] = { +#define DREG(x) { PCIE_REG_##x, #x } +#define DUTL(x) { PCIE_UTL_##x, "UTL_" #x } + /* Architected registers except CONFIG_ and IODA + * to avoid side effects + */ + DREG(DMA_CHAN_STATUS), + DREG(CPU_LOADSTORE_STATUS), + DREG(LOCK0), + DREG(LOCK1), + DREG(PHB_CONFIG), + DREG(IO_BASE_ADDR), + DREG(IO_BASE_MASK), + DREG(IO_START_ADDR), + DREG(M32A_BASE_ADDR), + DREG(M32A_BASE_MASK), + DREG(M32A_START_ADDR), + DREG(M32B_BASE_ADDR), + DREG(M32B_BASE_MASK), + DREG(M32B_START_ADDR), + DREG(M64_BASE_ADDR), + DREG(M64_BASE_MASK), + DREG(M64_START_ADDR), + DREG(TCE_KILL), + DREG(LOCK2), + DREG(PHB_GEN_CAP), + DREG(PHB_TCE_CAP), + DREG(PHB_IRQ_CAP), + DREG(PHB_EEH_CAP), + DREG(PAPR_ERR_INJ_CONTROL), + DREG(PAPR_ERR_INJ_ADDR), + DREG(PAPR_ERR_INJ_MASK), + + /* UTL core regs */ + DUTL(SYS_BUS_CONTROL), + DUTL(STATUS), + DUTL(SYS_BUS_AGENT_STATUS), + DUTL(SYS_BUS_AGENT_ERR_SEV), + DUTL(SYS_BUS_AGENT_IRQ_EN), + DUTL(SYS_BUS_BURST_SZ_CONF), + DUTL(REVISION_ID), + DUTL(OUT_POST_HDR_BUF_ALLOC), + DUTL(OUT_POST_DAT_BUF_ALLOC), + DUTL(IN_POST_HDR_BUF_ALLOC), + DUTL(IN_POST_DAT_BUF_ALLOC), + DUTL(OUT_NP_BUF_ALLOC), + DUTL(IN_NP_BUF_ALLOC), + DUTL(PCIE_TAGS_ALLOC), + DUTL(GBIF_READ_TAGS_ALLOC), + + DUTL(PCIE_PORT_CONTROL), + DUTL(PCIE_PORT_STATUS), + DUTL(PCIE_PORT_ERROR_SEV), + DUTL(PCIE_PORT_IRQ_EN), + DUTL(RC_STATUS), + DUTL(RC_ERR_SEVERITY), + DUTL(RC_IRQ_EN), + DUTL(EP_STATUS), + DUTL(EP_ERR_SEVERITY), + DUTL(EP_ERR_IRQ_EN), + DUTL(PCI_PM_CTRL1), + DUTL(PCI_PM_CTRL2), + + /* PCIe stack regs */ + DREG(SYSTEM_CONFIG1), + DREG(SYSTEM_CONFIG2), + DREG(EP_SYSTEM_CONFIG), + DREG(EP_FLR), + DREG(EP_BAR_CONFIG), + DREG(LINK_CONFIG), + DREG(PM_CONFIG), + DREG(DLP_CONTROL), + DREG(DLP_STATUS), + DREG(ERR_REPORT_CONTROL), + DREG(SLOT_CONTROL1), + DREG(SLOT_CONTROL2), + DREG(UTL_CONFIG), + DREG(BUFFERS_CONFIG), + DREG(ERROR_INJECT), + DREG(SRIOV_CONFIG), + DREG(PF0_SRIOV_STATUS), + DREG(PF1_SRIOV_STATUS), + DREG(PORT_NUMBER), + DREG(POR_SYSTEM_CONFIG), + + /* Internal logic regs */ + DREG(PHB_VERSION), + DREG(RESET), + DREG(PHB_CONTROL), + DREG(PHB_TIMEOUT_CONTROL1), + DREG(PHB_QUIESCE_DMA), + DREG(PHB_DMA_READ_TAG_ACTV), + DREG(PHB_TCE_READ_TAG_ACTV), + + /* FIR registers */ + DREG(LEM_FIR_ACCUM), + DREG(LEM_FIR_AND_MASK), + DREG(LEM_FIR_OR_MASK), + DREG(LEM_ACTION0), + DREG(LEM_ACTION1), + DREG(LEM_ERROR_MASK), + DREG(LEM_ERROR_AND_MASK), + DREG(LEM_ERROR_OR_MASK), + + /* Error traps registers */ + DREG(PHB_ERR_STATUS), + DREG(PHB_ERR_STATUS), + DREG(PHB_ERR1_STATUS), + DREG(PHB_ERR_INJECT), + DREG(PHB_ERR_LEM_ENABLE), + DREG(PHB_ERR_IRQ_ENABLE), + DREG(PHB_ERR_FREEZE_ENABLE), + DREG(PHB_ERR_SIDE_ENABLE), + DREG(PHB_ERR_LOG_0), + DREG(PHB_ERR_LOG_1), + DREG(PHB_ERR_STATUS_MASK), + DREG(PHB_ERR1_STATUS_MASK), + DREG(MMIO_ERR_STATUS), + DREG(MMIO_ERR1_STATUS), + DREG(MMIO_ERR_INJECT), + DREG(MMIO_ERR_LEM_ENABLE), + DREG(MMIO_ERR_IRQ_ENABLE), + DREG(MMIO_ERR_FREEZE_ENABLE), + DREG(MMIO_ERR_SIDE_ENABLE), + DREG(MMIO_ERR_LOG_0), + DREG(MMIO_ERR_LOG_1), + DREG(MMIO_ERR_STATUS_MASK), + DREG(MMIO_ERR1_STATUS_MASK), + DREG(DMA_ERR_STATUS), + DREG(DMA_ERR1_STATUS), + DREG(DMA_ERR_INJECT), + DREG(DMA_ERR_LEM_ENABLE), + DREG(DMA_ERR_IRQ_ENABLE), + DREG(DMA_ERR_FREEZE_ENABLE), + DREG(DMA_ERR_SIDE_ENABLE), + DREG(DMA_ERR_LOG_0), + DREG(DMA_ERR_LOG_1), + DREG(DMA_ERR_STATUS_MASK), + DREG(DMA_ERR1_STATUS_MASK), + + /* Debug and Trace registers */ + DREG(PHB_DEBUG_CONTROL0), + DREG(PHB_DEBUG_STATUS0), + DREG(PHB_DEBUG_CONTROL1), + DREG(PHB_DEBUG_STATUS1), + DREG(PHB_DEBUG_CONTROL2), + DREG(PHB_DEBUG_STATUS2), + DREG(PHB_DEBUG_CONTROL3), + DREG(PHB_DEBUG_STATUS3), + DREG(PHB_DEBUG_CONTROL4), + DREG(PHB_DEBUG_STATUS4), + DREG(PHB_DEBUG_CONTROL5), + DREG(PHB_DEBUG_STATUS5), + + /* Don't seem to exist ... + DREG(PHB_DEBUG_CONTROL6), + DREG(PHB_DEBUG_STATUS6), + */ +}; + +static int wsp_pci_regs_show(struct seq_file *m, void *private) +{ + struct wsp_phb *phb = m->private; + struct pci_controller *hose = phb->hose; + int i; + + for (i = 0; i < ARRAY_SIZE(wsp_pci_regs); i++) { + /* Skip write-only regs */ + if (wsp_pci_regs[i].offset == 0xc08 || + wsp_pci_regs[i].offset == 0xc10 || + wsp_pci_regs[i].offset == 0xc38 || + wsp_pci_regs[i].offset == 0xc40) + continue; + seq_printf(m, "0x%03x: 0x%016llx %s\n", + wsp_pci_regs[i].offset, + in_be64(hose->cfg_data + wsp_pci_regs[i].offset), + wsp_pci_regs[i].name); + } + return 0; +} + +static int wsp_pci_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, wsp_pci_regs_show, inode->i_private); +} + +static const struct file_operations wsp_pci_regs_fops = { + .open = wsp_pci_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int wsp_pci_reg_set(void *data, u64 val) +{ + out_be64((void __iomem *)data, val); + return 0; +} + +static int wsp_pci_reg_get(void *data, u64 *val) +{ + *val = in_be64((void __iomem *)data); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(wsp_pci_reg_fops, wsp_pci_reg_get, wsp_pci_reg_set, "0x%llx\n"); + +static irqreturn_t wsp_pci_err_irq(int irq, void *dev_id) +{ + struct wsp_phb *phb = dev_id; + struct pci_controller *hose = phb->hose; + irqreturn_t handled = IRQ_NONE; + struct wsp_pcie_err_log_data ed; + + pr_err("PCI: Error interrupt on %s (PHB %d)\n", + hose->dn->full_name, hose->global_number); + again: + memset(&ed, 0, sizeof(ed)); + + /* Read and clear UTL errors */ + ed.utl_sys_err = in_be64(hose->cfg_data + PCIE_UTL_SYS_BUS_AGENT_STATUS); + if (ed.utl_sys_err) + out_be64(hose->cfg_data + PCIE_UTL_SYS_BUS_AGENT_STATUS, ed.utl_sys_err); + ed.utl_port_err = in_be64(hose->cfg_data + PCIE_UTL_PCIE_PORT_STATUS); + if (ed.utl_port_err) + out_be64(hose->cfg_data + PCIE_UTL_PCIE_PORT_STATUS, ed.utl_port_err); + ed.utl_rc_err = in_be64(hose->cfg_data + PCIE_UTL_RC_STATUS); + if (ed.utl_rc_err) + out_be64(hose->cfg_data + PCIE_UTL_RC_STATUS, ed.utl_rc_err); + + /* Read and clear main trap errors */ + ed.phb_err = in_be64(hose->cfg_data + PCIE_REG_PHB_ERR_STATUS); + if (ed.phb_err) { + ed.phb_err1 = in_be64(hose->cfg_data + PCIE_REG_PHB_ERR1_STATUS); + ed.phb_log0 = in_be64(hose->cfg_data + PCIE_REG_PHB_ERR_LOG_0); + ed.phb_log1 = in_be64(hose->cfg_data + PCIE_REG_PHB_ERR_LOG_1); + out_be64(hose->cfg_data + PCIE_REG_PHB_ERR1_STATUS, 0); + out_be64(hose->cfg_data + PCIE_REG_PHB_ERR_STATUS, 0); + } + ed.mmio_err = in_be64(hose->cfg_data + PCIE_REG_MMIO_ERR_STATUS); + if (ed.mmio_err) { + ed.mmio_err1 = in_be64(hose->cfg_data + PCIE_REG_MMIO_ERR1_STATUS); + ed.mmio_log0 = in_be64(hose->cfg_data + PCIE_REG_MMIO_ERR_LOG_0); + ed.mmio_log1 = in_be64(hose->cfg_data + PCIE_REG_MMIO_ERR_LOG_1); + out_be64(hose->cfg_data + PCIE_REG_MMIO_ERR1_STATUS, 0); + out_be64(hose->cfg_data + PCIE_REG_MMIO_ERR_STATUS, 0); + } + ed.dma_err = in_be64(hose->cfg_data + PCIE_REG_DMA_ERR_STATUS); + if (ed.dma_err) { + ed.dma_err1 = in_be64(hose->cfg_data + PCIE_REG_DMA_ERR1_STATUS); + ed.dma_log0 = in_be64(hose->cfg_data + PCIE_REG_DMA_ERR_LOG_0); + ed.dma_log1 = in_be64(hose->cfg_data + PCIE_REG_DMA_ERR_LOG_1); + out_be64(hose->cfg_data + PCIE_REG_DMA_ERR1_STATUS, 0); + out_be64(hose->cfg_data + PCIE_REG_DMA_ERR_STATUS, 0); + } + + /* Now print things out */ + if (ed.phb_err) { + pr_err(" PHB Error Status : 0x%016llx\n", ed.phb_err); + pr_err(" PHB First Error Status: 0x%016llx\n", ed.phb_err1); + pr_err(" PHB Error Log 0 : 0x%016llx\n", ed.phb_log0); + pr_err(" PHB Error Log 1 : 0x%016llx\n", ed.phb_log1); + } + if (ed.mmio_err) { + pr_err(" MMIO Error Status : 0x%016llx\n", ed.mmio_err); + pr_err(" MMIO First Error Status: 0x%016llx\n", ed.mmio_err1); + pr_err(" MMIO Error Log 0 : 0x%016llx\n", ed.mmio_log0); + pr_err(" MMIO Error Log 1 : 0x%016llx\n", ed.mmio_log1); + } + if (ed.dma_err) { + pr_err(" DMA Error Status : 0x%016llx\n", ed.dma_err); + pr_err(" DMA First Error Status: 0x%016llx\n", ed.dma_err1); + pr_err(" DMA Error Log 0 : 0x%016llx\n", ed.dma_log0); + pr_err(" DMA Error Log 1 : 0x%016llx\n", ed.dma_log1); + } + if (ed.utl_sys_err) + pr_err(" UTL Sys Error Status : 0x%016llx\n", ed.utl_sys_err); + if (ed.utl_port_err) + pr_err(" UTL Port Error Status : 0x%016llx\n", ed.utl_port_err); + if (ed.utl_rc_err) + pr_err(" UTL RC Error Status : 0x%016llx\n", ed.utl_rc_err); + + /* Interrupts are caused by the error traps. If we had any error there + * we loop again in case the UTL buffered some new stuff between + * going there and going to the traps + */ + if (ed.dma_err || ed.mmio_err || ed.phb_err) { + handled = IRQ_HANDLED; + goto again; + } + return handled; +} + +static void __init wsp_setup_pci_err_reporting(struct wsp_phb *phb) +{ + struct pci_controller *hose = phb->hose; + int err_irq, i, rc; + char fname[16]; + + /* Create a debugfs file for that PHB */ + sprintf(fname, "phb%d", phb->hose->global_number); + phb->ddir = debugfs_create_dir(fname, powerpc_debugfs_root); + + /* Some useful debug output */ + if (phb->ddir) { + struct dentry *d = debugfs_create_dir("regs", phb->ddir); + char tmp[64]; + + for (i = 0; i < ARRAY_SIZE(wsp_pci_regs); i++) { + sprintf(tmp, "%03x_%s", wsp_pci_regs[i].offset, + wsp_pci_regs[i].name); + debugfs_create_file(tmp, 0600, d, + hose->cfg_data + wsp_pci_regs[i].offset, + &wsp_pci_reg_fops); + } + debugfs_create_file("all_regs", 0600, phb->ddir, phb, &wsp_pci_regs_fops); + } + + /* Find the IRQ number for that PHB */ + err_irq = irq_of_parse_and_map(hose->dn, 0); + if (err_irq == 0) + /* XXX Error IRQ lacking from device-tree */ + err_irq = wsp_pci_get_err_irq_no_dt(hose->dn); + if (err_irq == 0) { + pr_err("PCI: Failed to fetch error interrupt for %s\n", + hose->dn->full_name); + return; + } + /* Request it */ + rc = request_irq(err_irq, wsp_pci_err_irq, 0, "wsp_pci error", phb); + if (rc) { + pr_err("PCI: Failed to request interrupt for %s\n", + hose->dn->full_name); + } + /* Enable interrupts for all errors for now */ + out_be64(hose->cfg_data + PCIE_REG_PHB_ERR_IRQ_ENABLE, 0xffffffffffffffffull); + out_be64(hose->cfg_data + PCIE_REG_MMIO_ERR_IRQ_ENABLE, 0xffffffffffffffffull); + out_be64(hose->cfg_data + PCIE_REG_DMA_ERR_IRQ_ENABLE, 0xffffffffffffffffull); +} + +/* + * This is called later to hookup with the error interrupt + */ +static int __init wsp_setup_pci_late(void) +{ + struct wsp_phb *phb; + + list_for_each_entry(phb, &wsp_phbs, all) + wsp_setup_pci_err_reporting(phb); + + return 0; +} +arch_initcall(wsp_setup_pci_late); diff --git a/arch/powerpc/platforms/wsp/wsp_pci.h b/arch/powerpc/platforms/wsp/wsp_pci.h new file mode 100644 index 000000000000..52e9bd95250d --- /dev/null +++ b/arch/powerpc/platforms/wsp/wsp_pci.h @@ -0,0 +1,268 @@ +/* + * Copyright 2010 Ben Herrenschmidt, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __WSP_PCI_H +#define __WSP_PCI_H + +/* Architected registers */ +#define PCIE_REG_DMA_CHAN_STATUS 0x110 +#define PCIE_REG_CPU_LOADSTORE_STATUS 0x120 + +#define PCIE_REG_CONFIG_DATA 0x130 +#define PCIE_REG_LOCK0 0x138 +#define PCIE_REG_CONFIG_ADDRESS 0x140 +#define PCIE_REG_CA_ENABLE 0x8000000000000000ull +#define PCIE_REG_CA_BUS_MASK 0x0ff0000000000000ull +#define PCIE_REG_CA_BUS_SHIFT (20+32) +#define PCIE_REG_CA_DEV_MASK 0x000f800000000000ull +#define PCIE_REG_CA_DEV_SHIFT (15+32) +#define PCIE_REG_CA_FUNC_MASK 0x0000700000000000ull +#define PCIE_REG_CA_FUNC_SHIFT (12+32) +#define PCIE_REG_CA_REG_MASK 0x00000fff00000000ull +#define PCIE_REG_CA_REG_SHIFT ( 0+32) +#define PCIE_REG_CA_BE_MASK 0x00000000f0000000ull +#define PCIE_REG_CA_BE_SHIFT ( 28) +#define PCIE_REG_LOCK1 0x148 + +#define PCIE_REG_PHB_CONFIG 0x160 +#define PCIE_REG_PHBC_64B_TCE_EN 0x2000000000000000ull +#define PCIE_REG_PHBC_MMIO_DMA_FREEZE_EN 0x1000000000000000ull +#define PCIE_REG_PHBC_32BIT_MSI_EN 0x0080000000000000ull +#define PCIE_REG_PHBC_M64_EN 0x0040000000000000ull +#define PCIE_REG_PHBC_IO_EN 0x0008000000000000ull +#define PCIE_REG_PHBC_64BIT_MSI_EN 0x0002000000000000ull +#define PCIE_REG_PHBC_M32A_EN 0x0000800000000000ull +#define PCIE_REG_PHBC_M32B_EN 0x0000400000000000ull +#define PCIE_REG_PHBC_MSI_PE_VALIDATE 0x0000200000000000ull +#define PCIE_REG_PHBC_DMA_XLATE_BYPASS 0x0000100000000000ull + +#define PCIE_REG_IO_BASE_ADDR 0x170 +#define PCIE_REG_IO_BASE_MASK 0x178 +#define PCIE_REG_IO_START_ADDR 0x180 + +#define PCIE_REG_M32A_BASE_ADDR 0x190 +#define PCIE_REG_M32A_BASE_MASK 0x198 +#define PCIE_REG_M32A_START_ADDR 0x1a0 + +#define PCIE_REG_M32B_BASE_ADDR 0x1b0 +#define PCIE_REG_M32B_BASE_MASK 0x1b8 +#define PCIE_REG_M32B_START_ADDR 0x1c0 + +#define PCIE_REG_M64_BASE_ADDR 0x1e0 +#define PCIE_REG_M64_BASE_MASK 0x1e8 +#define PCIE_REG_M64_START_ADDR 0x1f0 + +#define PCIE_REG_TCE_KILL 0x210 +#define PCIE_REG_TCEKILL_SINGLE 0x8000000000000000ull +#define PCIE_REG_TCEKILL_ADDR_MASK 0x000003fffffffff8ull +#define PCIE_REG_TCEKILL_PS_4K 0 +#define PCIE_REG_TCEKILL_PS_64K 1 +#define PCIE_REG_TCEKILL_PS_16M 2 +#define PCIE_REG_TCEKILL_PS_16G 3 + +#define PCIE_REG_IODA_ADDR 0x220 +#define PCIE_REG_IODA_AD_AUTOINC 0x8000000000000000ull +#define PCIE_REG_IODA_AD_TBL_MVT 0x0005000000000000ull +#define PCIE_REG_IODA_AD_TBL_PELT 0x0006000000000000ull +#define PCIE_REG_IODA_AD_TBL_PESTA 0x0007000000000000ull +#define PCIE_REG_IODA_AD_TBL_PESTB 0x0008000000000000ull +#define PCIE_REG_IODA_AD_TBL_TVT 0x0009000000000000ull +#define PCIE_REG_IODA_AD_TBL_TCE 0x000a000000000000ull +#define PCIE_REG_IODA_DATA0 0x228 +#define PCIE_REG_IODA_DATA1 0x230 + +#define PCIE_REG_LOCK2 0x240 + +#define PCIE_REG_PHB_GEN_CAP 0x250 +#define PCIE_REG_PHB_TCE_CAP 0x258 +#define PCIE_REG_PHB_IRQ_CAP 0x260 +#define PCIE_REG_PHB_EEH_CAP 0x268 + +#define PCIE_REG_PAPR_ERR_INJ_CONTROL 0x2b0 +#define PCIE_REG_PAPR_ERR_INJ_ADDR 0x2b8 +#define PCIE_REG_PAPR_ERR_INJ_MASK 0x2c0 + + +#define PCIE_REG_SYS_CFG1 0x600 +#define PCIE_REG_SYS_CFG1_CLASS_CODE 0x0000000000ffffffull + +#define IODA_TVT0_TTA_MASK 0x000fffffffff0000ull +#define IODA_TVT0_TTA_SHIFT 4 +#define IODA_TVT0_BUSNUM_VALID_MASK 0x000000000000e000ull +#define IODA_TVT0_TCE_TABLE_SIZE_MASK 0x0000000000001f00ull +#define IODA_TVT0_TCE_TABLE_SIZE_SHIFT 8 +#define IODA_TVT0_BUSNUM_VALUE_MASK 0x00000000000000ffull +#define IODA_TVT0_BUSNUM_VALID_SHIFT 0 +#define IODA_TVT1_DEVNUM_VALID 0x2000000000000000ull +#define IODA_TVT1_DEVNUM_VALUE_MASK 0x1f00000000000000ull +#define IODA_TVT1_DEVNUM_VALUE_SHIFT 56 +#define IODA_TVT1_FUNCNUM_VALID 0x0008000000000000ull +#define IODA_TVT1_FUNCNUM_VALUE_MASK 0x0007000000000000ull +#define IODA_TVT1_FUNCNUM_VALUE_SHIFT 48 +#define IODA_TVT1_IO_PAGE_SIZE_MASK 0x00001f0000000000ull +#define IODA_TVT1_IO_PAGE_SIZE_SHIFT 40 +#define IODA_TVT1_PE_NUMBER_MASK 0x000000000000003full +#define IODA_TVT1_PE_NUMBER_SHIFT 0 + +#define IODA_TVT_COUNT 64 + +/* UTL Core registers */ +#define PCIE_UTL_SYS_BUS_CONTROL 0x400 +#define PCIE_UTL_STATUS 0x408 +#define PCIE_UTL_SYS_BUS_AGENT_STATUS 0x410 +#define PCIE_UTL_SYS_BUS_AGENT_ERR_SEV 0x418 +#define PCIE_UTL_SYS_BUS_AGENT_IRQ_EN 0x420 +#define PCIE_UTL_SYS_BUS_BURST_SZ_CONF 0x440 +#define PCIE_UTL_REVISION_ID 0x448 + +#define PCIE_UTL_OUT_POST_HDR_BUF_ALLOC 0x4c0 +#define PCIE_UTL_OUT_POST_DAT_BUF_ALLOC 0x4d0 +#define PCIE_UTL_IN_POST_HDR_BUF_ALLOC 0x4e0 +#define PCIE_UTL_IN_POST_DAT_BUF_ALLOC 0x4f0 +#define PCIE_UTL_OUT_NP_BUF_ALLOC 0x500 +#define PCIE_UTL_IN_NP_BUF_ALLOC 0x510 +#define PCIE_UTL_PCIE_TAGS_ALLOC 0x520 +#define PCIE_UTL_GBIF_READ_TAGS_ALLOC 0x530 + +#define PCIE_UTL_PCIE_PORT_CONTROL 0x540 +#define PCIE_UTL_PCIE_PORT_STATUS 0x548 +#define PCIE_UTL_PCIE_PORT_ERROR_SEV 0x550 +#define PCIE_UTL_PCIE_PORT_IRQ_EN 0x558 +#define PCIE_UTL_RC_STATUS 0x560 +#define PCIE_UTL_RC_ERR_SEVERITY 0x568 +#define PCIE_UTL_RC_IRQ_EN 0x570 +#define PCIE_UTL_EP_STATUS 0x578 +#define PCIE_UTL_EP_ERR_SEVERITY 0x580 +#define PCIE_UTL_EP_ERR_IRQ_EN 0x588 + +#define PCIE_UTL_PCI_PM_CTRL1 0x590 +#define PCIE_UTL_PCI_PM_CTRL2 0x598 + +/* PCIe stack registers */ +#define PCIE_REG_SYSTEM_CONFIG1 0x600 +#define PCIE_REG_SYSTEM_CONFIG2 0x608 +#define PCIE_REG_EP_SYSTEM_CONFIG 0x618 +#define PCIE_REG_EP_FLR 0x620 +#define PCIE_REG_EP_BAR_CONFIG 0x628 +#define PCIE_REG_LINK_CONFIG 0x630 +#define PCIE_REG_PM_CONFIG 0x640 +#define PCIE_REG_DLP_CONTROL 0x650 +#define PCIE_REG_DLP_STATUS 0x658 +#define PCIE_REG_ERR_REPORT_CONTROL 0x660 +#define PCIE_REG_SLOT_CONTROL1 0x670 +#define PCIE_REG_SLOT_CONTROL2 0x678 +#define PCIE_REG_UTL_CONFIG 0x680 +#define PCIE_REG_BUFFERS_CONFIG 0x690 +#define PCIE_REG_ERROR_INJECT 0x698 +#define PCIE_REG_SRIOV_CONFIG 0x6a0 +#define PCIE_REG_PF0_SRIOV_STATUS 0x6a8 +#define PCIE_REG_PF1_SRIOV_STATUS 0x6b0 +#define PCIE_REG_PORT_NUMBER 0x700 +#define PCIE_REG_POR_SYSTEM_CONFIG 0x708 + +/* PHB internal logic registers */ +#define PCIE_REG_PHB_VERSION 0x800 +#define PCIE_REG_RESET 0x808 +#define PCIE_REG_PHB_CONTROL 0x810 +#define PCIE_REG_PHB_TIMEOUT_CONTROL1 0x878 +#define PCIE_REG_PHB_QUIESCE_DMA 0x888 +#define PCIE_REG_PHB_DMA_READ_TAG_ACTV 0x900 +#define PCIE_REG_PHB_TCE_READ_TAG_ACTV 0x908 + +/* FIR registers */ +#define PCIE_REG_LEM_FIR_ACCUM 0xc00 +#define PCIE_REG_LEM_FIR_AND_MASK 0xc08 +#define PCIE_REG_LEM_FIR_OR_MASK 0xc10 +#define PCIE_REG_LEM_ACTION0 0xc18 +#define PCIE_REG_LEM_ACTION1 0xc20 +#define PCIE_REG_LEM_ERROR_MASK 0xc30 +#define PCIE_REG_LEM_ERROR_AND_MASK 0xc38 +#define PCIE_REG_LEM_ERROR_OR_MASK 0xc40 + +/* PHB Error registers */ +#define PCIE_REG_PHB_ERR_STATUS 0xc80 +#define PCIE_REG_PHB_ERR1_STATUS 0xc88 +#define PCIE_REG_PHB_ERR_INJECT 0xc90 +#define PCIE_REG_PHB_ERR_LEM_ENABLE 0xc98 +#define PCIE_REG_PHB_ERR_IRQ_ENABLE 0xca0 +#define PCIE_REG_PHB_ERR_FREEZE_ENABLE 0xca8 +#define PCIE_REG_PHB_ERR_SIDE_ENABLE 0xcb8 +#define PCIE_REG_PHB_ERR_LOG_0 0xcc0 +#define PCIE_REG_PHB_ERR_LOG_1 0xcc8 +#define PCIE_REG_PHB_ERR_STATUS_MASK 0xcd0 +#define PCIE_REG_PHB_ERR1_STATUS_MASK 0xcd8 + +#define PCIE_REG_MMIO_ERR_STATUS 0xd00 +#define PCIE_REG_MMIO_ERR1_STATUS 0xd08 +#define PCIE_REG_MMIO_ERR_INJECT 0xd10 +#define PCIE_REG_MMIO_ERR_LEM_ENABLE 0xd18 +#define PCIE_REG_MMIO_ERR_IRQ_ENABLE 0xd20 +#define PCIE_REG_MMIO_ERR_FREEZE_ENABLE 0xd28 +#define PCIE_REG_MMIO_ERR_SIDE_ENABLE 0xd38 +#define PCIE_REG_MMIO_ERR_LOG_0 0xd40 +#define PCIE_REG_MMIO_ERR_LOG_1 0xd48 +#define PCIE_REG_MMIO_ERR_STATUS_MASK 0xd50 +#define PCIE_REG_MMIO_ERR1_STATUS_MASK 0xd58 + +#define PCIE_REG_DMA_ERR_STATUS 0xd80 +#define PCIE_REG_DMA_ERR1_STATUS 0xd88 +#define PCIE_REG_DMA_ERR_INJECT 0xd90 +#define PCIE_REG_DMA_ERR_LEM_ENABLE 0xd98 +#define PCIE_REG_DMA_ERR_IRQ_ENABLE 0xda0 +#define PCIE_REG_DMA_ERR_FREEZE_ENABLE 0xda8 +#define PCIE_REG_DMA_ERR_SIDE_ENABLE 0xdb8 +#define PCIE_REG_DMA_ERR_LOG_0 0xdc0 +#define PCIE_REG_DMA_ERR_LOG_1 0xdc8 +#define PCIE_REG_DMA_ERR_STATUS_MASK 0xdd0 +#define PCIE_REG_DMA_ERR1_STATUS_MASK 0xdd8 + +/* Shortcuts for access to the above using the PHB definitions + * with an offset + */ +#define PCIE_REG_ERR_PHB_OFFSET 0x0 +#define PCIE_REG_ERR_MMIO_OFFSET 0x80 +#define PCIE_REG_ERR_DMA_OFFSET 0x100 + +/* Debug and Trace registers */ +#define PCIE_REG_PHB_DEBUG_CONTROL0 0xe00 +#define PCIE_REG_PHB_DEBUG_STATUS0 0xe08 +#define PCIE_REG_PHB_DEBUG_CONTROL1 0xe10 +#define PCIE_REG_PHB_DEBUG_STATUS1 0xe18 +#define PCIE_REG_PHB_DEBUG_CONTROL2 0xe20 +#define PCIE_REG_PHB_DEBUG_STATUS2 0xe28 +#define PCIE_REG_PHB_DEBUG_CONTROL3 0xe30 +#define PCIE_REG_PHB_DEBUG_STATUS3 0xe38 +#define PCIE_REG_PHB_DEBUG_CONTROL4 0xe40 +#define PCIE_REG_PHB_DEBUG_STATUS4 0xe48 +#define PCIE_REG_PHB_DEBUG_CONTROL5 0xe50 +#define PCIE_REG_PHB_DEBUG_STATUS5 0xe58 +#define PCIE_REG_PHB_DEBUG_CONTROL6 0xe60 +#define PCIE_REG_PHB_DEBUG_STATUS6 0xe68 + +/* Definition for PCIe errors */ +struct wsp_pcie_err_log_data { + __u64 phb_err; + __u64 phb_err1; + __u64 phb_log0; + __u64 phb_log1; + __u64 mmio_err; + __u64 mmio_err1; + __u64 mmio_log0; + __u64 mmio_log1; + __u64 dma_err; + __u64 dma_err1; + __u64 dma_log0; + __u64 dma_log1; + __u64 utl_sys_err; + __u64 utl_port_err; + __u64 utl_rc_err; + __u64 unused; +}; + +#endif /* __WSP_PCI_H */ From f9a71e0fd1b44148d7af6ce2fecfb2cf7a4df636 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 8 Aug 2011 12:30:55 +0000 Subject: [PATCH 0394/1596] powerpc/wsp: Add MSI support for PCI on PowerEN Based on a patch by Michael Ellerman Patch was simply forward ported upstream. Jimi Xenidis Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/wsp/Makefile | 1 + arch/powerpc/platforms/wsp/ics.c | 48 +++++++++++++ arch/powerpc/platforms/wsp/ics.h | 5 ++ arch/powerpc/platforms/wsp/msi.c | 102 ++++++++++++++++++++++++++++ arch/powerpc/platforms/wsp/msi.h | 19 ++++++ 5 files changed, 175 insertions(+) create mode 100644 arch/powerpc/platforms/wsp/msi.c create mode 100644 arch/powerpc/platforms/wsp/msi.h diff --git a/arch/powerpc/platforms/wsp/Makefile b/arch/powerpc/platforms/wsp/Makefile index 84519f8d8945..a1486b436f02 100644 --- a/arch/powerpc/platforms/wsp/Makefile +++ b/arch/powerpc/platforms/wsp/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PPC_PSR2) += psr2.o opb_pic.o obj-$(CONFIG_PPC_WSP) += scom_wsp.o obj-$(CONFIG_SMP) += smp.o scom_smp.o obj-$(CONFIG_PCI) += wsp_pci.o +obj-$(CONFIG_PCI_MSI) += msi.o \ No newline at end of file diff --git a/arch/powerpc/platforms/wsp/ics.c b/arch/powerpc/platforms/wsp/ics.c index e53bd9e7b125..576874392543 100644 --- a/arch/powerpc/platforms/wsp/ics.c +++ b/arch/powerpc/platforms/wsp/ics.c @@ -710,3 +710,51 @@ void __init wsp_init_irq(void) /* We need to patch our irq chip's EOI to point to the right ICP */ wsp_irq_chip.irq_eoi = icp_ops->eoi; } + +#ifdef CONFIG_PCI_MSI +static void wsp_ics_msi_unmask_irq(struct irq_data *d) +{ + wsp_chip_unmask_irq(d); + unmask_msi_irq(d); +} + +static unsigned int wsp_ics_msi_startup(struct irq_data *d) +{ + wsp_ics_msi_unmask_irq(d); + return 0; +} + +static void wsp_ics_msi_mask_irq(struct irq_data *d) +{ + mask_msi_irq(d); + wsp_chip_mask_irq(d); +} + +/* + * we do it this way because we reassinge default EOI handling in + * irq_init() above + */ +static void wsp_ics_eoi(struct irq_data *data) +{ + wsp_irq_chip.irq_eoi(data); +} + +static struct irq_chip wsp_ics_msi = { + .name = "WSP ICS MSI", + .irq_startup = wsp_ics_msi_startup, + .irq_mask = wsp_ics_msi_mask_irq, + .irq_unmask = wsp_ics_msi_unmask_irq, + .irq_eoi = wsp_ics_eoi, + .irq_set_affinity = wsp_chip_set_affinity +}; + +void wsp_ics_set_msi_chip(unsigned int irq) +{ + irq_set_chip(irq, &wsp_ics_msi); +} + +void wsp_ics_set_std_chip(unsigned int irq) +{ + irq_set_chip(irq, &wsp_irq_chip); +} +#endif /* CONFIG_PCI_MSI */ diff --git a/arch/powerpc/platforms/wsp/ics.h b/arch/powerpc/platforms/wsp/ics.h index e34d53102640..07b644e0cf97 100644 --- a/arch/powerpc/platforms/wsp/ics.h +++ b/arch/powerpc/platforms/wsp/ics.h @@ -17,4 +17,9 @@ extern void wsp_init_irq(void); extern int wsp_ics_alloc_irq(struct device_node *dn, int num); extern void wsp_ics_free_irq(struct device_node *dn, unsigned int irq); +#ifdef CONFIG_PCI_MSI +extern void wsp_ics_set_msi_chip(unsigned int irq); +extern void wsp_ics_set_std_chip(unsigned int irq); +#endif /* CONFIG_PCI_MSI */ + #endif /* __ICS_H */ diff --git a/arch/powerpc/platforms/wsp/msi.c b/arch/powerpc/platforms/wsp/msi.c new file mode 100644 index 000000000000..380882f27add --- /dev/null +++ b/arch/powerpc/platforms/wsp/msi.c @@ -0,0 +1,102 @@ +/* + * Copyright 2011 Michael Ellerman, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include "msi.h" +#include "ics.h" +#include "wsp_pci.h" + +/* Magic addresses for 32 & 64-bit MSIs with hardcoded MVE 0 */ +#define MSI_ADDR_32 0xFFFF0000ul +#define MSI_ADDR_64 0x1000000000000000ul + +int wsp_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + struct pci_controller *phb; + struct msi_desc *entry; + struct msi_msg msg; + unsigned int virq; + int hwirq; + + phb = pci_bus_to_host(dev->bus); + if (!phb) + return -ENOENT; + + entry = list_first_entry(&dev->msi_list, struct msi_desc, list); + if (entry->msi_attrib.is_64) { + msg.address_lo = 0; + msg.address_hi = MSI_ADDR_64 >> 32; + } else { + msg.address_lo = MSI_ADDR_32; + msg.address_hi = 0; + } + + list_for_each_entry(entry, &dev->msi_list, list) { + hwirq = wsp_ics_alloc_irq(phb->dn, 1); + if (hwirq < 0) { + dev_warn(&dev->dev, "wsp_msi: hwirq alloc failed!\n"); + return hwirq; + } + + virq = irq_create_mapping(NULL, hwirq); + if (virq == NO_IRQ) { + dev_warn(&dev->dev, "wsp_msi: virq alloc failed!\n"); + return -1; + } + + dev_dbg(&dev->dev, "wsp_msi: allocated irq %#x/%#x\n", + hwirq, virq); + + wsp_ics_set_msi_chip(virq); + irq_set_msi_desc(virq, entry); + msg.data = hwirq & XIVE_ADDR_MASK; + write_msi_msg(virq, &msg); + } + + return 0; +} + +void wsp_teardown_msi_irqs(struct pci_dev *dev) +{ + struct pci_controller *phb; + struct msi_desc *entry; + int hwirq; + + phb = pci_bus_to_host(dev->bus); + + dev_dbg(&dev->dev, "wsp_msi: tearing down msi irqs\n"); + + list_for_each_entry(entry, &dev->msi_list, list) { + if (entry->irq == NO_IRQ) + continue; + + irq_set_msi_desc(entry->irq, NULL); + wsp_ics_set_std_chip(entry->irq); + + hwirq = virq_to_hw(entry->irq); + /* In this order to avoid racing with irq_create_mapping() */ + irq_dispose_mapping(entry->irq); + wsp_ics_free_irq(phb->dn, hwirq); + } +} + +void wsp_setup_phb_msi(struct pci_controller *phb) +{ + /* Create a single MVE at offset 0 that matches everything */ + out_be64(phb->cfg_data + PCIE_REG_IODA_ADDR, PCIE_REG_IODA_AD_TBL_MVT); + out_be64(phb->cfg_data + PCIE_REG_IODA_DATA0, 1ull << 63); + + ppc_md.setup_msi_irqs = wsp_setup_msi_irqs; + ppc_md.teardown_msi_irqs = wsp_teardown_msi_irqs; +} diff --git a/arch/powerpc/platforms/wsp/msi.h b/arch/powerpc/platforms/wsp/msi.h new file mode 100644 index 000000000000..0ab27b71b24d --- /dev/null +++ b/arch/powerpc/platforms/wsp/msi.h @@ -0,0 +1,19 @@ +/* + * Copyright 2011 Michael Ellerman, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __WSP_MSI_H +#define __WSP_MSI_H + +#ifdef CONFIG_PCI_MSI +extern void wsp_setup_phb_msi(struct pci_controller *phb); +#else +static inline void wsp_setup_phb_msi(struct pci_controller *phb) { } +#endif + +#endif /* __WSP_MSI_H */ From 9c57a32b2f1615e0ad77e9d3b68fd720f43430da Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Wed, 10 Aug 2011 20:16:54 +0000 Subject: [PATCH 0395/1596] powerpc/4xx/pci: Add __init annotations for *init_port_hw() functions. The various port_init_hw methods of ppc4xx_pciex_hwops should have been marked __init and when I added ppc4xx_pciex_port_reset_sdr(), which is __init. This added many section mismatch warnings like: WARNING: arch/powerpc/sysdev/built-in.o(.text+0x5c68): Section mismatch in reference from the function ppc440spe_pciex_init_port_hw() to the function .init.text:ppc4xx_pciex_port_reset_sdr() The function ppc440spe_pciex_init_port_hw() references the function __init ppc4xx_pciex_port_reset_sdr(). This is often because ppc440spe_pciex_init_port_hw lacks a __init annotation or the annotation of ppc4xx_pciex_port_reset_sdr is wrong. Trivial patch to silence those warnings. Reported-By: Stephen Rothwell Signed-off-by: Tony Breeds Yours Tony Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/ppc4xx_pci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 2ec046d0a394..862f11b3821e 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -834,7 +834,7 @@ static int __init ppc440spe_pciex_core_init(struct device_node *np) return 3; } -static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val = 1 << 24; @@ -872,12 +872,12 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) return ppc4xx_pciex_port_reset_sdr(port); } -static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { return ppc440spe_pciex_init_port_hw(port); } -static int ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { int rc = ppc440spe_pciex_init_port_hw(port); @@ -936,7 +936,7 @@ static int __init ppc460ex_pciex_core_init(struct device_node *np) return 2; } -static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val; u32 utlset1; @@ -1126,7 +1126,7 @@ static int __init ppc460sx_pciex_core_init(struct device_node *np) return 2; } -static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { if (port->endpoint) @@ -1218,7 +1218,7 @@ static void ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port) mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000); } -static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +static int __init ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) { u32 val; From 0330581ab3b9002d55ee66f377ccbbb742175c01 Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Tue, 16 Aug 2011 19:51:33 +0000 Subject: [PATCH 0396/1596] powerpc/mm: Fix the call trace when resumed from hibernation In SMP mode, the kernel would produce call trace when resumed from hibernation. The reason is when the function destroy_context is called to drop the resuming mm context, the mm->context.active is 1 which is wrong and should be zero. We pass the current->active_mm as previous mm context to function switch_mmu_context to decrease the context.active by 1. In UP mode, there is no effect. Signed-off-by: Tang Yuantian Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/swsusp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c index aa17b76dd427..641f9adc6205 100644 --- a/arch/powerpc/kernel/swsusp.c +++ b/arch/powerpc/kernel/swsusp.c @@ -33,6 +33,6 @@ void save_processor_state(void) void restore_processor_state(void) { #ifdef CONFIG_PPC32 - switch_mmu_context(NULL, current->active_mm); + switch_mmu_context(current->active_mm, current->active_mm); #endif } From 9c740025c51a26ab00192cfc464064d4ccbfe3fc Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 14 Aug 2011 14:30:30 +0000 Subject: [PATCH 0397/1596] powerpc/pseries: Avoid spurious error during hotplug CPU add During hotplug CPU add we get the following error: Unexpected Error (0) returned from configure-connector ibm,configure-connector returns 0 for configuration complete, so catch this and avoid the error. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Cc: --- arch/powerpc/platforms/pseries/dlpar.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index e9be25bc571b..0f1b706506ed 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -112,6 +112,7 @@ void dlpar_free_cc_nodes(struct device_node *dn) dlpar_free_one_cc_node(dn); } +#define COMPLETE 0 #define NEXT_SIBLING 1 #define NEXT_CHILD 2 #define NEXT_PROPERTY 3 @@ -158,6 +159,9 @@ struct device_node *dlpar_configure_connector(u32 drc_index) spin_unlock(&rtas_data_buf_lock); switch (rc) { + case COMPLETE: + break; + case NEXT_SIBLING: dn = dlpar_parse_cc_node(ccwa); if (!dn) From cf01a404d96f9bf6f514074579f0a2d355bfa38e Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Thu, 25 Aug 2011 06:07:13 +0000 Subject: [PATCH 0398/1596] powerpc/xics: Add __init to marker icp_native_init() This should fix the following warning: LD arch/powerpc/sysdev/xics/built-in.o WARNING: arch/powerpc/sysdev/xics/built-in.o(.text+0x1310): Section mismatch in reference from the function .icp_native_init() to the function .init.text:.icp_native_init_one_node() The function .icp_native_init() references the function __init .icp_native_init_one_node(). This is often because .icp_native_init lacks a __init annotation or the annotation of .icp_native_init_one_node is wrong. icp_native_init() is only referenced in `arch/powerpc/sysdev/xics/xics-common.c' by xics_init() which is itself marked with __init. = not built-tested = Reported-by: Timur Tabi Signed-off-by: Arnaud Lacombe Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/xics/icp-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index 50e32afe392e..4c79b6fbee1c 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -276,7 +276,7 @@ static const struct icp_ops icp_native_ops = { #endif }; -int icp_native_init(void) +int __init icp_native_init(void) { struct device_node *np; u32 indx = 0; From 8feaa43494cee5e938fd5a57b9e9bf1c827e6ccd Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Fri, 26 Aug 2011 10:36:31 +0000 Subject: [PATCH 0399/1596] powerpc/eeh: Fix /proc/ppc64/eeh creation Since commit 188917e183cf9ad0374b571006d0fc6d48a7f447, /proc/ppc64 is a symlink to /proc/powerpc/. That means that creating /proc/ppc64/eeh will end up with a unaccessible file, that is not listed under /proc/powerpc/ and, then, not listed under /proc/ppc64/. Creating /proc/powerpc/eeh fixes that problem and maintain the compatibility intended with the ppc64 symlink. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Benjamin Herrenschmidt Cc: [3.x] --- arch/powerpc/platforms/pseries/eeh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index ada6e07532ec..d42f37d8a440 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -1338,7 +1338,7 @@ static const struct file_operations proc_eeh_operations = { static int __init eeh_init_proc(void) { if (machine_is(pseries)) - proc_create("ppc64/eeh", 0, NULL, &proc_eeh_operations); + proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations); return 0; } __initcall(eeh_init_proc); From c26afe9e8591f306d79aab8071f1d34e4f60b700 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 31 Aug 2011 06:32:26 +0000 Subject: [PATCH 0400/1596] powerpc/ps3: Add gelic udbg driver Add a new udbg driver for the PS3 gelic Ehthernet device. This driver shares only a few stucture and constant definitions with the gelic Ethernet device driver, so is implemented as a stand-alone driver with no dependencies on the gelic Ethernet device driver. Signed-off-by: Hector Martin Signed-off-by: Andre Heider Signed-off-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig.debug | 8 + arch/powerpc/include/asm/udbg.h | 1 + arch/powerpc/kernel/udbg.c | 2 + arch/powerpc/platforms/ps3/Kconfig | 12 ++ arch/powerpc/platforms/ps3/Makefile | 1 + arch/powerpc/platforms/ps3/gelic_udbg.c | 273 ++++++++++++++++++++++++ drivers/net/ps3_gelic_net.c | 3 + drivers/net/ps3_gelic_net.h | 6 + 8 files changed, 306 insertions(+) create mode 100644 arch/powerpc/platforms/ps3/gelic_udbg.c diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 067cb8480747..ab2335f160a0 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -258,6 +258,14 @@ config PPC_EARLY_DEBUG_WSP depends on PPC_WSP select PPC_UDBG_16550 +config PPC_EARLY_DEBUG_PS3GELIC + bool "Early debugging through the PS3 Ethernet port" + depends on PPC_PS3 + select PS3GELIC_UDBG + help + Select this to enable early debugging for the PlayStation3 via + UDP broadcasts sent out through the Ethernet port. + endchoice config PPC_EARLY_DEBUG_HVSI_VTERMNO diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h index 93e05d1b34b2..7cf796fa03f2 100644 --- a/arch/powerpc/include/asm/udbg.h +++ b/arch/powerpc/include/asm/udbg.h @@ -54,6 +54,7 @@ extern void __init udbg_init_40x_realmode(void); extern void __init udbg_init_cpm(void); extern void __init udbg_init_usbgecko(void); extern void __init udbg_init_wsp(void); +extern void __init udbg_init_ps3gelic(void); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_UDBG_H */ diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index faa82c1f3f68..5b3e98e03158 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -67,6 +67,8 @@ void __init udbg_early_init(void) udbg_init_usbgecko(); #elif defined(CONFIG_PPC_EARLY_DEBUG_WSP) udbg_init_wsp(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC) + udbg_init_ps3gelic(); #endif #ifdef CONFIG_PPC_EARLY_DEBUG diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index dfe316b161a9..476d9d9b2405 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -148,4 +148,16 @@ config PS3_LPM profiling support of the Cell processor with programs like oprofile and perfmon2, then say Y or M, otherwise say N. +config PS3GELIC_UDBG + bool "PS3 udbg output via UDP broadcasts on Ethernet" + depends on PPC_PS3 + help + Enables udbg early debugging output by sending broadcast UDP + via the Ethernet port (UDP port number 18194). + + This driver uses a trivial implementation and is independent + from the main network driver. + + If in doubt, say N here. + endmenu diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index ac1bdf844eca..02b9e636dab7 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile @@ -2,6 +2,7 @@ obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o obj-y += interrupt.o exports.o os-area.o obj-y += system-bus.o +obj-$(CONFIG_PS3GELIC_UDBG) += gelic_udbg.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SPU_BASE) += spu.o obj-y += device-init.o diff --git a/arch/powerpc/platforms/ps3/gelic_udbg.c b/arch/powerpc/platforms/ps3/gelic_udbg.c new file mode 100644 index 000000000000..20b46a19a48f --- /dev/null +++ b/arch/powerpc/platforms/ps3/gelic_udbg.c @@ -0,0 +1,273 @@ +/* + * udbg debug output routine via GELIC UDP broadcasts + * + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * Copyright 2006, 2007 Sony Corporation + * Copyright (C) 2010 Hector Martin + * Copyright (C) 2011 Andre Heider + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + */ + +#include +#include +#include + +#define GELIC_BUS_ID 1 +#define GELIC_DEVICE_ID 0 +#define GELIC_DEBUG_PORT 18194 +#define GELIC_MAX_MESSAGE_SIZE 1000 + +#define GELIC_LV1_GET_MAC_ADDRESS 1 +#define GELIC_LV1_GET_VLAN_ID 4 +#define GELIC_LV1_VLAN_TX_ETHERNET_0 2 + +#define GELIC_DESCR_DMA_STAT_MASK 0xf0000000 +#define GELIC_DESCR_DMA_CARDOWNED 0xa0000000 + +#define GELIC_DESCR_TX_DMA_IKE 0x00080000 +#define GELIC_DESCR_TX_DMA_NO_CHKSUM 0x00000000 +#define GELIC_DESCR_TX_DMA_FRAME_TAIL 0x00040000 + +#define GELIC_DESCR_DMA_CMD_NO_CHKSUM (GELIC_DESCR_DMA_CARDOWNED | \ + GELIC_DESCR_TX_DMA_IKE | \ + GELIC_DESCR_TX_DMA_NO_CHKSUM) + +static u64 bus_addr; + +struct gelic_descr { + /* as defined by the hardware */ + __be32 buf_addr; + __be32 buf_size; + __be32 next_descr_addr; + __be32 dmac_cmd_status; + __be32 result_size; + __be32 valid_size; /* all zeroes for tx */ + __be32 data_status; + __be32 data_error; /* all zeroes for tx */ +} __attribute__((aligned(32))); + +struct debug_block { + struct gelic_descr descr; + u8 pkt[1520]; +} __packed; + +struct ethhdr { + u8 dest[6]; + u8 src[6]; + u16 type; +} __packed; + +struct vlantag { + u16 vlan; + u16 subtype; +} __packed; + +struct iphdr { + u8 ver_len; + u8 dscp_ecn; + u16 total_length; + u16 ident; + u16 frag_off_flags; + u8 ttl; + u8 proto; + u16 checksum; + u32 src; + u32 dest; +} __packed; + +struct udphdr { + u16 src; + u16 dest; + u16 len; + u16 checksum; +} __packed; + +static __iomem struct ethhdr *h_eth; +static __iomem struct vlantag *h_vlan; +static __iomem struct iphdr *h_ip; +static __iomem struct udphdr *h_udp; + +static __iomem char *pmsg; +static __iomem char *pmsgc; + +static __iomem struct debug_block dbg __attribute__((aligned(32))); + +static int header_size; + +static void map_dma_mem(int bus_id, int dev_id, void *start, size_t len, + u64 *real_bus_addr) +{ + s64 result; + u64 real_addr = ((u64)start) & 0x0fffffffffffffffUL; + u64 real_end = real_addr + len; + u64 map_start = real_addr & ~0xfff; + u64 map_end = (real_end + 0xfff) & ~0xfff; + u64 bus_addr = 0; + + u64 flags = 0xf800000000000000UL; + + result = lv1_allocate_device_dma_region(bus_id, dev_id, + map_end - map_start, 12, 0, + &bus_addr); + if (result) + lv1_panic(0); + + result = lv1_map_device_dma_region(bus_id, dev_id, map_start, + bus_addr, map_end - map_start, + flags); + if (result) + lv1_panic(0); + + *real_bus_addr = bus_addr + real_addr - map_start; +} + +static int unmap_dma_mem(int bus_id, int dev_id, u64 bus_addr, size_t len) +{ + s64 result; + u64 real_bus_addr; + + real_bus_addr = bus_addr & ~0xfff; + len += bus_addr - real_bus_addr; + len = (len + 0xfff) & ~0xfff; + + result = lv1_unmap_device_dma_region(bus_id, dev_id, real_bus_addr, + len); + if (result) + return result; + + return lv1_free_device_dma_region(bus_id, dev_id, real_bus_addr); +} + +static void gelic_debug_init(void) +{ + s64 result; + u64 v2; + u64 mac; + u64 vlan_id; + + result = lv1_open_device(GELIC_BUS_ID, GELIC_DEVICE_ID, 0); + if (result) + lv1_panic(0); + + map_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, &dbg, sizeof(dbg), + &bus_addr); + + memset(&dbg, 0, sizeof(dbg)); + + dbg.descr.buf_addr = bus_addr + offsetof(struct debug_block, pkt); + + wmb(); + + result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID, + GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0, + &mac, &v2); + if (result) + lv1_panic(0); + + mac <<= 16; + + h_eth = (struct ethhdr *)dbg.pkt; + + memset(&h_eth->dest, 0xff, 6); + memcpy(&h_eth->src, &mac, 6); + + header_size = sizeof(struct ethhdr); + + result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID, + GELIC_LV1_GET_VLAN_ID, + GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0, + &vlan_id, &v2); + if (!result) { + h_eth->type = 0x8100; + + header_size += sizeof(struct vlantag); + h_vlan = (struct vlantag *)(h_eth + 1); + h_vlan->vlan = vlan_id; + h_vlan->subtype = 0x0800; + h_ip = (struct iphdr *)(h_vlan + 1); + } else { + h_eth->type = 0x0800; + h_ip = (struct iphdr *)(h_eth + 1); + } + + header_size += sizeof(struct iphdr); + h_ip->ver_len = 0x45; + h_ip->ttl = 10; + h_ip->proto = 0x11; + h_ip->src = 0x00000000; + h_ip->dest = 0xffffffff; + + header_size += sizeof(struct udphdr); + h_udp = (struct udphdr *)(h_ip + 1); + h_udp->src = GELIC_DEBUG_PORT; + h_udp->dest = GELIC_DEBUG_PORT; + + pmsgc = pmsg = (char *)(h_udp + 1); +} + +static void gelic_debug_shutdown(void) +{ + if (bus_addr) + unmap_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, + bus_addr, sizeof(dbg)); + lv1_close_device(GELIC_BUS_ID, GELIC_DEVICE_ID); +} + +static void gelic_sendbuf(int msgsize) +{ + u16 *p; + u32 sum; + int i; + + dbg.descr.buf_size = header_size + msgsize; + h_ip->total_length = msgsize + sizeof(struct udphdr) + + sizeof(struct iphdr); + h_udp->len = msgsize + sizeof(struct udphdr); + + h_ip->checksum = 0; + sum = 0; + p = (u16 *)h_ip; + for (i = 0; i < 5; i++) + sum += *p++; + h_ip->checksum = ~(sum + (sum >> 16)); + + dbg.descr.dmac_cmd_status = GELIC_DESCR_DMA_CMD_NO_CHKSUM | + GELIC_DESCR_TX_DMA_FRAME_TAIL; + dbg.descr.result_size = 0; + dbg.descr.data_status = 0; + + wmb(); + + lv1_net_start_tx_dma(GELIC_BUS_ID, GELIC_DEVICE_ID, bus_addr, 0); + + while ((dbg.descr.dmac_cmd_status & GELIC_DESCR_DMA_STAT_MASK) == + GELIC_DESCR_DMA_CARDOWNED) + cpu_relax(); +} + +static void ps3gelic_udbg_putc(char ch) +{ + *pmsgc++ = ch; + if (ch == '\n' || (pmsgc-pmsg) >= GELIC_MAX_MESSAGE_SIZE) { + gelic_sendbuf(pmsgc-pmsg); + pmsgc = pmsg; + } +} + +void __init udbg_init_ps3gelic(void) +{ + gelic_debug_init(); + udbg_putc = ps3gelic_udbg_putc; +} + +void udbg_shutdown_ps3gelic(void) +{ + udbg_putc = NULL; + gelic_debug_shutdown(); +} +EXPORT_SYMBOL(udbg_shutdown_ps3gelic); diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index d82a82d9870c..e743c9418ac9 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1674,6 +1674,9 @@ static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) int result; pr_debug("%s: called\n", __func__); + + udbg_shutdown_ps3gelic(); + result = ps3_open_hv_device(dev); if (result) { diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index d3fadfbc3bcc..a93df6ac1909 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -359,6 +359,12 @@ static inline void *port_priv(struct gelic_port *port) return port->priv; } +#ifdef CONFIG_PPC_EARLY_DEBUG_PS3GELIC +extern void udbg_shutdown_ps3gelic(void); +#else +static inline void udbg_shutdown_ps3gelic(void) {} +#endif + extern int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask); /* shared netdev ops */ extern void gelic_card_up(struct gelic_card *card); From a200d8e44649de2cbb39de95f42ad4ef5dc8dc22 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 24 Jul 2011 16:33:12 +0000 Subject: [PATCH 0401/1596] powerpc/numa: Enable SD_WAKE_AFFINE in node definition When chasing a performance issue on ppc64, I noticed tasks communicating via a pipe would often end up on different nodes. It turns out SD_WAKE_AFFINE is not set in our node defition. Commit 9fcd18c9e63e (sched: re-tune balancing) enabled SD_WAKE_AFFINE in the node definition for x86 and we need a similar change for ppc64. I used lmbench lat_ctx and perf bench pipe to verify this fix. Each benchmark was run 10 times and the average taken. lmbench lat_ctx: before: 66565 ops/sec after: 204700 ops/sec 3.1x faster perf bench pipe: before: 5.6570 usecs after: 1.3470 usecs 4.2x faster Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/topology.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 7ef0d90defc8..6a7e7251cc02 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -73,7 +73,7 @@ static inline int pcibus_to_node(struct pci_bus *bus) | 1*SD_BALANCE_EXEC \ | 1*SD_BALANCE_FORK \ | 0*SD_BALANCE_WAKE \ - | 0*SD_WAKE_AFFINE \ + | 1*SD_WAKE_AFFINE \ | 0*SD_PREFER_LOCAL \ | 0*SD_SHARE_CPUPOWER \ | 0*SD_POWERSAVINGS_BALANCE \ From 590e4d857153c5d4cf86052cdfd42cf9b0779841 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 24 Jul 2011 16:33:13 +0000 Subject: [PATCH 0402/1596] sched: Allow SD_NODES_PER_DOMAIN to be overridden We want to override the default value of SD_NODES_PER_DOMAIN on ppc64, so move it into linux/topology.h. Signed-off-by: Anton Blanchard Acked-by: Peter Zijlstra Signed-off-by: Benjamin Herrenschmidt --- include/linux/topology.h | 4 ++++ kernel/sched.c | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/topology.h b/include/linux/topology.h index fc839bfa7935..e26db031303b 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -201,6 +201,10 @@ int arch_update_cpu_topology(void); .balance_interval = 64, \ } +#ifndef SD_NODES_PER_DOMAIN +#define SD_NODES_PER_DOMAIN 16 +#endif + #ifdef CONFIG_SCHED_BOOK #ifndef SD_BOOK_INIT #error Please define an appropriate SD_BOOK_INIT in include/asm/topology.h!!! diff --git a/kernel/sched.c b/kernel/sched.c index ec5f472bc5b9..d258b2d9a66d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6947,8 +6947,6 @@ static int __init isolated_cpu_setup(char *str) __setup("isolcpus=", isolated_cpu_setup); -#define SD_NODES_PER_DOMAIN 16 - #ifdef CONFIG_NUMA /** From d4761ad2ef18ec2c9a0037d6649c0afc4a7b907d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 24 Jul 2011 16:33:14 +0000 Subject: [PATCH 0403/1596] powerpc/numa: Increase SD_NODES_PER_DOMAIN to 32. The largest POWER7 boxes have 32 nodes. SD_NODES_PER_DOMAIN groups nodes into chunks of 16 and adds a global balancing domain (SD_ALLNODES) above it. If we bump SD_NODES_PER_DOMAIN to 32, then we avoid this extra level of balancing on our largest boxes. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/topology.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 6a7e7251cc02..d1c1d312f808 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -28,6 +28,12 @@ struct device_node; */ #define RECLAIM_DISTANCE 10 +/* + * Avoid creating an extra level of balancing (SD_ALLNODES) on the largest + * POWER7 boxes which have a maximum of 32 nodes. + */ +#define SD_NODES_PER_DOMAIN 32 + #include static inline int cpu_to_node(int cpu) From 7bebcf0925f09224393a8992af706fa39aa10395 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 24 Jul 2011 16:33:15 +0000 Subject: [PATCH 0404/1596] powerpc/numa: Disable NEWIDLE balancing at node level On big POWER7 boxes we see large amounts of CPU time in system processes like workqueue and watchdog kernel threads. We currently rebalance the entire machine each time a task goes idle and this is very expensive on large machines. Disable newidle balancing at the node level and rely on the scheduler tick to rebalance across nodes. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/topology.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index d1c1d312f808..13efa4d95e76 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -75,7 +75,7 @@ static inline int pcibus_to_node(struct pci_bus *bus) .forkexec_idx = 0, \ \ .flags = 1*SD_LOAD_BALANCE \ - | 1*SD_BALANCE_NEWIDLE \ + | 0*SD_BALANCE_NEWIDLE \ | 1*SD_BALANCE_EXEC \ | 1*SD_BALANCE_FORK \ | 0*SD_BALANCE_WAKE \ From e377bc5d49fdbcb5f0e559b644d806a15454d407 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 24 Jul 2011 16:33:16 +0000 Subject: [PATCH 0405/1596] powerpc/numa: Remove duplicate RECLAIM_DISTANCE definition We have two identical definitions of RECLAIM_DISTANCE, looks like the patch got applied twice. Remove one. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/topology.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 13efa4d95e76..1e104af08483 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -18,16 +18,6 @@ struct device_node; */ #define RECLAIM_DISTANCE 10 -/* - * Before going off node we want the VM to try and reclaim from the local - * node. It does this if the remote distance is larger than RECLAIM_DISTANCE. - * With the default REMOTE_DISTANCE of 20 and the default RECLAIM_DISTANCE of - * 20, we never reclaim and go off node straight away. - * - * To fix this we choose a smaller value of RECLAIM_DISTANCE. - */ -#define RECLAIM_DISTANCE 10 - /* * Avoid creating an extra level of balancing (SD_ALLNODES) on the largest * POWER7 boxes which have a maximum of 32 nodes. From 6083184269fd723affca4f6340e491950267622a Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 10 Aug 2011 20:44:21 +0000 Subject: [PATCH 0406/1596] powerpc/numa: Remove double of_node_put in hot_add_node_scn_to_nid During memory hotplug testing, I got the following warning: ERROR: Bad of_node_put() on /memory@0 of_node_release kref_put of_node_put of_find_node_by_type hot_add_node_scn_to_nid hot_add_scn_to_nid memory_add_physaddr_to_nid ... of_find_node_by_type() loop does the of_node_put for us so we only need the handle the case where we terminate the loop early. As suggested by Stephen Rothwell we can do the of_node_put unconditionally outside of the loop since of_node_put handles a NULL argument fine. Signed-off-by: Anton Blanchard Cc: stable@kernel.org Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/numa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 2164006fe170..2c1ae7a5fb53 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -1214,11 +1214,12 @@ int hot_add_node_scn_to_nid(unsigned long scn_addr) break; } - of_node_put(memory); if (nid >= 0) break; } + of_node_put(memory); + return nid; } From 94db7c5e14f44b943febe54e089d077cd983d284 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 10 Aug 2011 20:44:22 +0000 Subject: [PATCH 0407/1596] powerpc: Use for_each_node_by_type instead of open coding it Use for_each_node_by_type instead of open coding it. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/machine_kexec_64.c | 3 +-- arch/powerpc/kernel/setup_64.c | 2 +- arch/powerpc/mm/numa.c | 10 +++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 583af70c4b14..26ccbf77dd41 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -74,8 +74,7 @@ int default_machine_kexec_prepare(struct kimage *image) } /* We also should not overwrite the tce tables */ - for (node = of_find_node_by_type(NULL, "pci"); node != NULL; - node = of_find_node_by_type(node, "pci")) { + for_each_node_by_type(node, "pci") { basep = of_get_property(node, "linux,tce-base", NULL); sizep = of_get_property(node, "linux,tce-size", NULL); if (basep == NULL || sizep == NULL) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index aebef1320ed7..eade1fd8ee2e 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -278,7 +278,7 @@ static void __init initialize_cache_info(void) DBG(" -> initialize_cache_info()\n"); - for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { + for_each_node_by_type(np, "cpu") { num_cpus += 1; /* We're assuming *all* of the CPUs have the same diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 2c1ae7a5fb53..00cc090cd1dc 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -710,7 +710,7 @@ static void __init parse_drconf_memory(struct device_node *memory) static int __init parse_numa_properties(void) { struct device_node *cpu = NULL; - struct device_node *memory = NULL; + struct device_node *memory; int default_nid = 0; unsigned long i; @@ -750,8 +750,8 @@ static int __init parse_numa_properties(void) } get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells); - memory = NULL; - while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { + + for_each_node_by_type(memory, "memory") { unsigned long start; unsigned long size; int nid; @@ -1187,10 +1187,10 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory, */ int hot_add_node_scn_to_nid(unsigned long scn_addr) { - struct device_node *memory = NULL; + struct device_node *memory; int nid = -1; - while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { + for_each_node_by_type(memory, "memory") { unsigned long start, size; int ranges; const unsigned int *memcell_buf; From dfbe93a222e74b6f96ad84eff2b04a0f864fac65 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 10 Aug 2011 20:44:23 +0000 Subject: [PATCH 0408/1596] powerpc: Coding style cleanups While converting code to use for_each_node_by_type I noticed a number of coding style issues. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/setup_64.c | 20 +++++++++++++------- arch/powerpc/mm/numa.c | 7 ++++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index eade1fd8ee2e..d4168c93098f 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -281,11 +281,11 @@ static void __init initialize_cache_info(void) for_each_node_by_type(np, "cpu") { num_cpus += 1; - /* We're assuming *all* of the CPUs have the same + /* + * We're assuming *all* of the CPUs have the same * d-cache and i-cache sizes... -Peter */ - - if ( num_cpus == 1 ) { + if (num_cpus == 1) { const u32 *sizep, *lsizep; u32 size, lsize; @@ -294,10 +294,13 @@ static void __init initialize_cache_info(void) sizep = of_get_property(np, "d-cache-size", NULL); if (sizep != NULL) size = *sizep; - lsizep = of_get_property(np, "d-cache-block-size", NULL); + lsizep = of_get_property(np, "d-cache-block-size", + NULL); /* fallback if block size missing */ if (lsizep == NULL) - lsizep = of_get_property(np, "d-cache-line-size", NULL); + lsizep = of_get_property(np, + "d-cache-line-size", + NULL); if (lsizep != NULL) lsize = *lsizep; if (sizep == 0 || lsizep == 0) @@ -314,9 +317,12 @@ static void __init initialize_cache_info(void) sizep = of_get_property(np, "i-cache-size", NULL); if (sizep != NULL) size = *sizep; - lsizep = of_get_property(np, "i-cache-block-size", NULL); + lsizep = of_get_property(np, "i-cache-block-size", + NULL); if (lsizep == NULL) - lsizep = of_get_property(np, "i-cache-line-size", NULL); + lsizep = of_get_property(np, + "i-cache-line-size", + NULL); if (lsizep != NULL) lsize = *lsizep; if (sizep == 0 || lsizep == 0) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 00cc090cd1dc..0bfb90c50571 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -709,7 +709,6 @@ static void __init parse_drconf_memory(struct device_node *memory) static int __init parse_numa_properties(void) { - struct device_node *cpu = NULL; struct device_node *memory; int default_nid = 0; unsigned long i; @@ -732,6 +731,7 @@ static int __init parse_numa_properties(void) * each node to be onlined must have NODE_DATA etc backing it. */ for_each_present_cpu(i) { + struct device_node *cpu; int nid; cpu = of_get_cpu_node(i, NULL); @@ -800,8 +800,9 @@ static int __init parse_numa_properties(void) } /* - * Now do the same thing for each MEMBLOCK listed in the ibm,dynamic-memory - * property in the ibm,dynamic-reconfiguration-memory node. + * Now do the same thing for each MEMBLOCK listed in the + * ibm,dynamic-memory property in the + * ibm,dynamic-reconfiguration-memory node. */ memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); if (memory) From a11940978bd598e65996b4f807cf4904793f7025 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 10 Aug 2011 20:44:24 +0000 Subject: [PATCH 0409/1596] powerpc: Fix oops when echoing bad values to /sys/devices/system/memory/probe If we echo an address the hypervisor doesn't like to /sys/devices/system/memory/probe we oops the box: # echo 0x10000000000 > /sys/devices/system/memory/probe kernel BUG at arch/powerpc/mm/hash_utils_64.c:541! The backtrace is: create_section_mapping arch_add_memory add_memory memory_probe_store sysdev_class_store sysfs_write_file vfs_write SyS_write In create_section_mapping we BUG if htab_bolt_mapping returned an error. A better approach is to return an error which will propagate back to userspace. Rerunning the test with this patch applied: # echo 0x10000000000 > /sys/devices/system/memory/probe -bash: echo: write error: Invalid argument Signed-off-by: Anton Blanchard Cc: stable@kernel.org Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/sparsemem.h | 2 +- arch/powerpc/mm/hash_utils_64.c | 6 +++--- arch/powerpc/mm/mem.c | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h index 54a47ea2c3aa..0c5fa3145615 100644 --- a/arch/powerpc/include/asm/sparsemem.h +++ b/arch/powerpc/include/asm/sparsemem.h @@ -16,7 +16,7 @@ #endif /* CONFIG_SPARSEMEM */ #ifdef CONFIG_MEMORY_HOTPLUG -extern void create_section_mapping(unsigned long start, unsigned long end); +extern int create_section_mapping(unsigned long start, unsigned long end); extern int remove_section_mapping(unsigned long start, unsigned long end); #ifdef CONFIG_NUMA extern int hot_add_scn_to_nid(unsigned long scn_addr); diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 1f8b2a05e3d0..1628201c8cea 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -531,11 +531,11 @@ static unsigned long __init htab_get_table_size(void) } #ifdef CONFIG_MEMORY_HOTPLUG -void create_section_mapping(unsigned long start, unsigned long end) +int create_section_mapping(unsigned long start, unsigned long end) { - BUG_ON(htab_bolt_mapping(start, end, __pa(start), + return htab_bolt_mapping(start, end, __pa(start), pgprot_val(PAGE_KERNEL), mmu_linear_psize, - mmu_kernel_ssize)); + mmu_kernel_ssize); } int remove_section_mapping(unsigned long start, unsigned long end) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index ad9cf49dfb89..5db316cad47b 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -123,7 +123,8 @@ int arch_add_memory(int nid, u64 start, u64 size) pgdata = NODE_DATA(nid); start = (unsigned long)__va(start); - create_section_mapping(start, start + size); + if (create_section_mapping(start, start + size)) + return -EINVAL; /* this should work for most non-highmem platforms */ zone = pgdata->node_zones; From 8bdafa39a47265bc029838b35cc6585f69224afa Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 14 Sep 2011 09:43:15 +0000 Subject: [PATCH 0410/1596] powerpc: Fix deadlock in icswx code The icswx code introduced an A-B B-A deadlock: CPU0 CPU1 ---- ---- lock(&anon_vma->mutex); lock(&mm->mmap_sem); lock(&anon_vma->mutex); lock(&mm->mmap_sem); Instead of using the mmap_sem to keep mm_users constant, take the page table spinlock. Signed-off-by: Anton Blanchard Cc: Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/mmu_context_hash64.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index 3bafc3deca6d..4ff587e38250 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -136,8 +136,8 @@ int use_cop(unsigned long acop, struct mm_struct *mm) if (!mm || !acop) return -EINVAL; - /* We need to make sure mm_users doesn't change */ - down_read(&mm->mmap_sem); + /* The page_table_lock ensures mm_users won't change under us */ + spin_lock(&mm->page_table_lock); spin_lock(mm->context.cop_lockp); if (mm->context.cop_pid == COP_PID_NONE) { @@ -164,7 +164,7 @@ int use_cop(unsigned long acop, struct mm_struct *mm) out: spin_unlock(mm->context.cop_lockp); - up_read(&mm->mmap_sem); + spin_unlock(&mm->page_table_lock); return ret; } @@ -185,8 +185,8 @@ void drop_cop(unsigned long acop, struct mm_struct *mm) if (WARN_ON_ONCE(!mm)) return; - /* We need to make sure mm_users doesn't change */ - down_read(&mm->mmap_sem); + /* The page_table_lock ensures mm_users won't change under us */ + spin_lock(&mm->page_table_lock); spin_lock(mm->context.cop_lockp); mm->context.acop &= ~acop; @@ -213,7 +213,7 @@ void drop_cop(unsigned long acop, struct mm_struct *mm) } spin_unlock(mm->context.cop_lockp); - up_read(&mm->mmap_sem); + spin_unlock(&mm->page_table_lock); } EXPORT_SYMBOL_GPL(drop_cop); From ac07a4a57f7408922a0b3d4dcb87104fe8a3d8ca Mon Sep 17 00:00:00 2001 From: Brian King Date: Tue, 13 Sep 2011 11:22:51 +0000 Subject: [PATCH 0411/1596] hvcs: Ensure page aligned partner info buffer The Power platform requires the partner info buffer to be page aligned otherwise it will fail the partner info hcall with H_PARAMETER. Switch from using kmalloc to allocate this buffer to __get_free_page to ensure page alignment. Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt --- drivers/tty/hvc/hvcs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 4c8b66546930..39291665eca3 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1532,7 +1532,7 @@ static int __devinit hvcs_initialize(void) goto register_fail; } - hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); + hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL); if (!hvcs_pi_buff) { rc = -ENOMEM; goto buff_alloc_fail; @@ -1548,7 +1548,7 @@ static int __devinit hvcs_initialize(void) return 0; kthread_fail: - kfree(hvcs_pi_buff); + free_page((unsigned long)hvcs_pi_buff); buff_alloc_fail: tty_unregister_driver(hvcs_tty_driver); register_fail: @@ -1597,7 +1597,7 @@ static void __exit hvcs_module_exit(void) kthread_stop(hvcs_task); spin_lock(&hvcs_pi_lock); - kfree(hvcs_pi_buff); + free_page((unsigned long)hvcs_pi_buff); hvcs_pi_buff = NULL; spin_unlock(&hvcs_pi_lock); From b8bb922c680b7e21af2268bc8eec93b17f5b9ab8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:48 +0000 Subject: [PATCH 0412/1596] powerpc/udbg: Fix Kconfig entry for avoiding 44x early debug with KVM It was preventing the global early debug selection whenever KVM was enabled instead of only preventing the 440 specific one. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig.debug | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index ab2335f160a0..06eb62b0fd90 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -141,9 +141,6 @@ config BOOTX_TEXT config PPC_EARLY_DEBUG bool "Early debugging (dangerous)" - # PPC_EARLY_DEBUG on 440 leaves AS=1 mappings above the TLB high water - # mark, which doesn't work with current 440 KVM. - depends on !KVM help Say Y to enable some early debugging facilities that may be available for your processor/board combination. Those facilities are hacks @@ -222,7 +219,9 @@ config PPC_EARLY_DEBUG_BEAT config PPC_EARLY_DEBUG_44x bool "Early serial debugging for IBM/AMCC 44x CPUs" - depends on 44x + # PPC_EARLY_DEBUG on 440 leaves AS=1 mappings above the TLB high water + # mark, which doesn't work with current 440 KVM. + depends on 44x && !KVM help Select this to enable early debugging for IBM 44x chips via the inbuilt serial port. If you enable this, ensure you set From fb82b83970a32263698e54a8779d2ce88cd3b060 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:49 +0000 Subject: [PATCH 0413/1596] powerpc/smp: More generic support for "soft hotplug" This adds more generic support for doing CPU hotplug with a simple idle loop and no actual reset of the processors. The generic smp_generic_kick_cpu() does the hotplug bringup trick if the PACA shows that the CPU has already been started at boot and we provide an accessor for the CPU state. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/smp.h | 1 + arch/powerpc/kernel/smp.c | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 15a70b7f638b..adba970ce918 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -65,6 +65,7 @@ int generic_cpu_disable(void); void generic_cpu_die(unsigned int cpu); void generic_mach_cpu_die(void); void generic_set_cpu_dead(unsigned int cpu); +int generic_check_cpu_restart(unsigned int cpu); #endif #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 7bf2187dfd99..af7e7722ecae 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -70,6 +70,10 @@ static DEFINE_PER_CPU(struct task_struct *, idle_thread_array); #define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x)) #define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p)) + +/* State of each CPU during hotplug phases */ +static DEFINE_PER_CPU(int, cpu_state) = { 0 }; + #else static struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ; #define get_idle_for_cpu(x) (idle_thread_array[(x)]) @@ -104,12 +108,25 @@ int __devinit smp_generic_kick_cpu(int nr) * cpu_start field to become non-zero After we set cpu_start, * the processor will continue on to secondary_start */ - paca[nr].cpu_start = 1; - smp_mb(); + if (!paca[nr].cpu_start) { + paca[nr].cpu_start = 1; + smp_mb(); + return 0; + } + +#ifdef CONFIG_HOTPLUG_CPU + /* + * Ok it's not there, so it might be soft-unplugged, let's + * try to bring it back + */ + per_cpu(cpu_state, nr) = CPU_UP_PREPARE; + smp_wmb(); + smp_send_reschedule(nr); +#endif /* CONFIG_HOTPLUG_CPU */ return 0; } -#endif +#endif /* CONFIG_PPC64 */ static irqreturn_t call_function_action(int irq, void *data) { @@ -357,8 +374,6 @@ void __devinit smp_prepare_boot_cpu(void) } #ifdef CONFIG_HOTPLUG_CPU -/* State of each CPU during hotplug phases */ -static DEFINE_PER_CPU(int, cpu_state) = { 0 }; int generic_cpu_disable(void) { @@ -406,6 +421,11 @@ void generic_set_cpu_dead(unsigned int cpu) { per_cpu(cpu_state, cpu) = CPU_DEAD; } + +int generic_check_cpu_restart(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; +} #endif struct create_idle { From 781fb7a3e4cdca28236ae23e2c77070ed3ae531f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:50 +0000 Subject: [PATCH 0414/1596] powerpc/pci: Call pcie_bus_configure_settings() This new function is used to properly setup the PCI Express Max Payload Size (and in some circumstances Max Read Request Size). Some systems will not operate properly if these aren't set correctly and the firmware doesn't always do it. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/pci-common.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 32656f105250..1bd47f36b25f 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1730,6 +1730,17 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose) if (mode == PCI_PROBE_NORMAL) hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); + + /* Configure PCI Express settings */ + if (bus) { + struct pci_bus *child; + list_for_each_entry(child, &bus->children, node) { + struct pci_dev *self = child->self; + if (!self) + continue; + pcie_bus_configure_settings(child, self->pcie_mpss); + } + } } static void fixup_hide_host_resource_fsl(struct pci_dev *dev) From e550592e689cf8d682937f356497f989f3d88292 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:51 +0000 Subject: [PATCH 0415/1596] powerpc/powernv: Don't clobber r9 in relative_toc() With OPAL, r8 and r9 will be used to pass the OPAL base and entry for debugging purposes (those informations are also in the device-tree). We don't want to clobber those registers that early. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/head_64.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 3564c49c683e..e708abe576d3 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -674,9 +674,9 @@ _GLOBAL(enable_64b_mode) _GLOBAL(relative_toc) mflr r0 bcl 20,31,$+4 -0: mflr r9 - ld r2,(p_toc - 0b)(r9) - add r2,r2,r9 +0: mflr r11 + ld r2,(p_toc - 0b)(r11) + add r2,r2,r11 mtlr r0 blr From 55190f88789ab62a42c3ee050090406b0bcefff8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:52 +0000 Subject: [PATCH 0416/1596] powerpc: Add skeleton PowerNV platform This adds a skeletton for the new Power "Non Virtualized" platform which will be used by machines supporting running without an hypervisor, for example in order to run KVM. These machines will be using a new firmware called OPAL for which the support will be provided by later patches. The PowerNV platform is intended to be also usable under the BML environment used internally for early CPU bringup which is why the code also supports using RTAS instead of OPAL in various places. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/boot/Makefile | 1 + arch/powerpc/platforms/Kconfig | 1 + arch/powerpc/platforms/Makefile | 1 + arch/powerpc/platforms/powernv/Kconfig | 11 ++ arch/powerpc/platforms/powernv/Makefile | 2 + arch/powerpc/platforms/powernv/powernv.h | 10 ++ arch/powerpc/platforms/powernv/setup.c | 153 +++++++++++++++++++++++ arch/powerpc/platforms/powernv/smp.c | 83 ++++++++++++ 8 files changed, 262 insertions(+) create mode 100644 arch/powerpc/platforms/powernv/Kconfig create mode 100644 arch/powerpc/platforms/powernv/Makefile create mode 100644 arch/powerpc/platforms/powernv/powernv.h create mode 100644 arch/powerpc/platforms/powernv/setup.c create mode 100644 arch/powerpc/platforms/powernv/smp.c diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index ac6705e75711..72ee8c1fba48 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -171,6 +171,7 @@ quiet_cmd_wrap = WRAP $@ $(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux image-$(CONFIG_PPC_PSERIES) += zImage.pseries +image-$(CONFIG_PPC_POWERNV) += zImage.pseries image-$(CONFIG_PPC_MAPLE) += zImage.maple image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries image-$(CONFIG_PPC_PS3) += dtbImage.ps3 diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index b9ba86191aed..6de27d275728 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -1,5 +1,6 @@ menu "Platform support" +source "arch/powerpc/platforms/powernv/Kconfig" source "arch/powerpc/platforms/pseries/Kconfig" source "arch/powerpc/platforms/iseries/Kconfig" source "arch/powerpc/platforms/chrp/Kconfig" diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 73e2116cfeed..2635a22bade2 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_PPC_82xx) += 82xx/ obj-$(CONFIG_PPC_83xx) += 83xx/ obj-$(CONFIG_FSL_SOC_BOOKE) += 85xx/ obj-$(CONFIG_PPC_86xx) += 86xx/ +obj-$(CONFIG_PPC_POWERNV) += powernv/ obj-$(CONFIG_PPC_PSERIES) += pseries/ obj-$(CONFIG_PPC_ISERIES) += iseries/ obj-$(CONFIG_PPC_MAPLE) += maple/ diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig new file mode 100644 index 000000000000..24700e8df19c --- /dev/null +++ b/arch/powerpc/platforms/powernv/Kconfig @@ -0,0 +1,11 @@ +config PPC_POWERNV + depends on PPC64 && PPC_BOOK3S + bool "IBM PowerNV (Non-Virtualized) platform support" + select PPC_RTAS + select PPC_NATIVE + select PPC_XICS + select PPC_ICP_NATIVE + select PPC_ICS_RTAS + select PPC_P7_NAP + select PPC_PCI_CHOICE if EMBEDDED + default y diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile new file mode 100644 index 000000000000..1c4325056b85 --- /dev/null +++ b/arch/powerpc/platforms/powernv/Makefile @@ -0,0 +1,2 @@ +obj-y += setup.o +obj-$(CONFIG_SMP) += smp.o diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h new file mode 100644 index 000000000000..35b716008cd3 --- /dev/null +++ b/arch/powerpc/platforms/powernv/powernv.h @@ -0,0 +1,10 @@ +#ifndef _POWERNV_H +#define _POWERNV_H + +#ifdef CONFIG_SMP +extern void pnv_smp_init(void); +#else +static inline void pnv_smp_init(void) { } +#endif + +#endif /* _POWERNV_H */ diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c new file mode 100644 index 000000000000..569f9cc4eb04 --- /dev/null +++ b/arch/powerpc/platforms/powernv/setup.c @@ -0,0 +1,153 @@ +/* + * PowerNV setup code. + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "powernv.h" + +static void __init pnv_setup_arch(void) +{ + /* Force console to hvc for now until we have sorted out the + * real console situation for the platform. This will make + * hvc_udbg work at least. + */ + add_preferred_console("hvc", 0, NULL); + + /* Initialize SMP */ + pnv_smp_init(); + + /* XXX PCI */ + + /* XXX NVRAM */ + + /* Enable NAP mode */ + powersave_nap = 1; + + /* XXX PMCS */ +} + +static void __init pnv_init_early(void) +{ + /* XXX IOMMU */ +} + +static void __init pnv_init_IRQ(void) +{ + xics_init(); + + WARN_ON(!ppc_md.get_irq); +} + +static void pnv_show_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + const char *model = ""; + + root = of_find_node_by_path("/"); + if (root) + model = of_get_property(root, "model", NULL); + seq_printf(m, "machine\t\t: PowerNV %s\n", model); + of_node_put(root); +} + +static void pnv_restart(char *cmd) +{ + for (;;); +} + +static void pnv_power_off(void) +{ + for (;;); +} + +static void pnv_halt(void) +{ + for (;;); +} + +static unsigned long __init pnv_get_boot_time(void) +{ + return 0; +} + +static void pnv_get_rtc_time(struct rtc_time *rtc_tm) +{ +} + +static int pnv_set_rtc_time(struct rtc_time *tm) +{ + return 0; +} + +static void pnv_progress(char *s, unsigned short hex) +{ +} + +#ifdef CONFIG_KEXEC +static void pnv_kexec_cpu_down(int crash_shutdown, int secondary) +{ + xics_kexec_teardown_cpu(secondary); +} +#endif /* CONFIG_KEXEC */ + +static int __init pnv_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,powernv")) + return 0; + + hpte_init_native(); + + pr_debug("PowerNV detected !\n"); + + return 1; +} + +define_machine(powernv) { + .name = "PowerNV", + .probe = pnv_probe, + .setup_arch = pnv_setup_arch, + .init_early = pnv_init_early, + .init_IRQ = pnv_init_IRQ, + .show_cpuinfo = pnv_show_cpuinfo, + .restart = pnv_restart, + .power_off = pnv_power_off, + .halt = pnv_halt, + .get_boot_time = pnv_get_boot_time, + .get_rtc_time = pnv_get_rtc_time, + .set_rtc_time = pnv_set_rtc_time, + .progress = pnv_progress, + .power_save = power7_idle, + .calibrate_decr = generic_calibrate_decr, +#ifdef CONFIG_KEXEC + .kexec_cpu_down = pnv_kexec_cpu_down, +#endif +}; diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c new file mode 100644 index 000000000000..36c715102c58 --- /dev/null +++ b/arch/powerpc/platforms/powernv/smp.c @@ -0,0 +1,83 @@ +/* + * SMP support for PowerNV machines. + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "powernv.h" + +static void __devinit pnv_smp_setup_cpu(int cpu) +{ + if (cpu != boot_cpuid) + xics_setup_cpu(); +} + +static int pnv_smp_cpu_bootable(unsigned int nr) +{ + /* Special case - we inhibit secondary thread startup + * during boot if the user requests it. + */ + if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) { + if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) + return 0; + if (smt_enabled_at_boot + && cpu_thread_in_core(nr) >= smt_enabled_at_boot) + return 0; + } + + return 1; +} + +static struct smp_ops_t pnv_smp_ops = { + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */ + .probe = xics_smp_probe, + .kick_cpu = smp_generic_kick_cpu, + .setup_cpu = pnv_smp_setup_cpu, + .cpu_bootable = pnv_smp_cpu_bootable, +}; + +/* This is called very early during platform setup_arch */ +void __init pnv_smp_init(void) +{ + smp_ops = &pnv_smp_ops; + + /* XXX We don't yet have a proper entry point from HAL, for + * now we rely on kexec-style entry from BML + */ + +#ifdef CONFIG_PPC_RTAS + /* Non-lpar has additional take/give timebase */ + if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) { + smp_ops->give_timebase = rtas_give_timebase; + smp_ops->take_timebase = rtas_take_timebase; + } +#endif /* CONFIG_PPC_RTAS */ +} From 78b782cb788cadbda151ecb61753c109602a250c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 18:50:15 +0000 Subject: [PATCH 0417/1596] of: Change logic to overwrite cmd_line with CONFIG_CMDLINE We used to overwrite with CONFIG_CMDLINE if we found a chosen node but failed to get bootargs out of it or they were empty, unless CONFIG_CMDLINE_FORCE is set. Instead change that to overwrite if "data" is non empty after the bootargs check. It allows arch code to have other mechanisms to retrieve the command line prior to parsing the device-tree. Note: CONFIG_CMDLINE_FORCE case should ideally be handled elsewhere as it won't work as it-is if the device-tree has no /chosen node Signed-off-by: Benjamin Herrenschmidt CC: devicetree-discuss@lists-ozlabs.org CC: Grant Likely Acked-by: Grant Likely --- drivers/of/fdt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 65200af29c52..4af69a3564cc 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -681,9 +681,14 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, if (p != NULL && l > 0) strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else + * managed to set the command line, unless CONFIG_CMDLINE_FORCE + * is set in which case we override whatever was found earlier. + */ #ifdef CONFIG_CMDLINE #ifndef CONFIG_CMDLINE_FORCE - if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) + if (!((char *)data)[0]) #endif strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); #endif /* CONFIG_CMDLINE */ From 344eb010b2e399069bac474a9fd0ba04908a2601 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:54 +0000 Subject: [PATCH 0418/1596] powerpc/powernv: Add CPU hotplug support Unplugged CPU go into NAP mode in a loop until woken up Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig | 2 +- arch/powerpc/platforms/powernv/smp.c | 78 +++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 62711421cd64..8523bd1b8d7e 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -323,7 +323,7 @@ config SWIOTLB config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" - depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC) + depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index 36c715102c58..4f4ec3797eb6 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -33,7 +33,14 @@ #include "powernv.h" -static void __devinit pnv_smp_setup_cpu(int cpu) +#ifdef DEBUG +#include +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +static void __cpuinit pnv_smp_setup_cpu(int cpu) { if (cpu != boot_cpuid) xics_setup_cpu(); @@ -55,6 +62,67 @@ static int pnv_smp_cpu_bootable(unsigned int nr) return 1; } +#ifdef CONFIG_HOTPLUG_CPU + +static int pnv_smp_cpu_disable(void) +{ + int cpu = smp_processor_id(); + + /* This is identical to pSeries... might consolidate by + * moving migrate_irqs_away to a ppc_md with default to + * the generic fixup_irqs. --BenH. + */ + set_cpu_online(cpu, false); + vdso_data->processorCount--; + if (cpu == boot_cpuid) + boot_cpuid = cpumask_any(cpu_online_mask); + xics_migrate_irqs_away(); + return 0; +} + +static void pnv_smp_cpu_kill_self(void) +{ + unsigned int cpu; + + /* If powersave_nap is enabled, use NAP mode, else just + * spin aimlessly + */ + if (!powersave_nap) { + generic_mach_cpu_die(); + return; + } + + /* Standard hot unplug procedure */ + local_irq_disable(); + idle_task_exit(); + current->active_mm = NULL; /* for sanity */ + cpu = smp_processor_id(); + DBG("CPU%d offline\n", cpu); + generic_set_cpu_dead(cpu); + smp_wmb(); + + /* We don't want to take decrementer interrupts while we are offline, + * so clear LPCR:PECE1. We keep PECE2 enabled. + */ + mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); + while (!generic_check_cpu_restart(cpu)) { + power7_idle(); + if (!generic_check_cpu_restart(cpu)) { + DBG("CPU%d Unexpected exit while offline !\n", cpu); + /* We may be getting an IPI, so we re-enable + * interrupts to process it, it will be ignored + * since we aren't online (hopefully) + */ + local_irq_enable(); + local_irq_disable(); + } + } + mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1); + DBG("CPU%d coming online...\n", cpu); +} + +#endif /* CONFIG_HOTPLUG_CPU */ + static struct smp_ops_t pnv_smp_ops = { .message_pass = smp_muxed_ipi_message_pass, .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */ @@ -62,6 +130,10 @@ static struct smp_ops_t pnv_smp_ops = { .kick_cpu = smp_generic_kick_cpu, .setup_cpu = pnv_smp_setup_cpu, .cpu_bootable = pnv_smp_cpu_bootable, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = pnv_smp_cpu_disable, + .cpu_die = generic_cpu_die, +#endif /* CONFIG_HOTPLUG_CPU */ }; /* This is called very early during platform setup_arch */ @@ -80,4 +152,8 @@ void __init pnv_smp_init(void) smp_ops->take_timebase = rtas_take_timebase; } #endif /* CONFIG_PPC_RTAS */ + +#ifdef CONFIG_HOTPLUG_CPU + ppc_md.cpu_die = pnv_smp_cpu_kill_self; +#endif } From 27f4488872d9ef2a4b9aa2be58fb0789d6c0ba84 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 18:27:58 +0000 Subject: [PATCH 0419/1596] powerpc/powernv: Add OPAL takeover from PowerVM On machines supporting the OPAL firmware version 1, the system is initially booted under pHyp. We then use a special hypercall to verify if OPAL is available and if it is, we then trigger a "takeover" which disables pHyp and loads the OPAL runtime firmware, giving control to the kernel in hypervisor mode. This patch add the necessary code to detect that the OPAL takeover capability is present when running under PowerVM (aka pHyp) and perform said takeover to get hypervisor control of the processor. To perform the takeover, we must first use RTAS (within Open Firmware runtime environment) to start all processors & threads, in order to give control to OPAL on all of them. We then call the takeover hypercall on everybody, OPAL will re-enter the kernel main entry point passing it a flat device-tree. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/opal.h | 50 ++++ arch/powerpc/kernel/head_64.S | 4 + arch/powerpc/kernel/prom_init.c | 239 ++++++++++++++++-- arch/powerpc/kernel/prom_init_check.sh | 3 +- arch/powerpc/platforms/powernv/Makefile | 2 +- .../powerpc/platforms/powernv/opal-takeover.S | 140 ++++++++++ 6 files changed, 419 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/include/asm/opal.h create mode 100644 arch/powerpc/platforms/powernv/opal-takeover.S diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h new file mode 100644 index 000000000000..ecdb283f8b7c --- /dev/null +++ b/arch/powerpc/include/asm/opal.h @@ -0,0 +1,50 @@ +/* + * PowerNV OPAL definitions. + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __OPAL_H +#define __OPAL_H + +/****** Takeover interface ********/ + +/* PAPR H-Call used to querty the HAL existence and/or instanciate + * it from within pHyp (tech preview only). + * + * This is exclusively used in prom_init.c + */ + +#ifndef __ASSEMBLY__ + +struct opal_takeover_args { + u64 k_image; /* r4 */ + u64 k_size; /* r5 */ + u64 k_entry; /* r6 */ + u64 k_entry2; /* r7 */ + u64 hal_addr; /* r8 */ + u64 rd_image; /* r9 */ + u64 rd_size; /* r10 */ + u64 rd_loc; /* r11 */ +}; + +extern long opal_query_takeover(u64 *hal_size, u64 *hal_align); + +extern long opal_do_takeover(struct opal_takeover_args *args); + +extern int opal_enter_rtas(struct rtas_args *args, + unsigned long data, + unsigned long entry); + + +#endif /* __ASSEMBLY__ */ + +/****** OPAL APIs ******/ + + +#endif /* __OPAL_H */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index e708abe576d3..dea8191253d2 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -51,6 +51,10 @@ * For pSeries or server processors: * 1. The MMU is off & open firmware is running in real mode. * 2. The kernel is entered at __start + * -or- For OPAL entry: + * 1. The MMU is off, processor in HV mode, primary CPU enters at 0 + * with device-tree in gpr3 + * 2. Secondary processors enter at 0x60 with PIR in gpr3 * * For iSeries: * 1. The MMU is on (as it always is for iSeries) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index a909f4e9343b..9369287aa8c2 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -185,6 +186,7 @@ static unsigned long __initdata prom_tce_alloc_end; #define PLATFORM_LPAR 0x0001 #define PLATFORM_POWERMAC 0x0400 #define PLATFORM_GENERIC 0x0500 +#define PLATFORM_OPAL 0x0600 static int __initdata of_platform; @@ -644,7 +646,7 @@ static void __init early_cmdline_parse(void) } } -#ifdef CONFIG_PPC_PSERIES +#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) /* * There are two methods for telling firmware what our capabilities are. * Newer machines have an "ibm,client-architecture-support" method on the @@ -1274,6 +1276,195 @@ static void __init prom_init_mem(void) prom_printf(" ram_top : %x\n", RELOC(ram_top)); } +static void __init prom_close_stdin(void) +{ + struct prom_t *_prom = &RELOC(prom); + ihandle val; + + if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0) + call_prom("close", 1, 0, val); +} + +#ifdef CONFIG_PPC_POWERNV + +static u64 __initdata prom_opal_size; +static u64 __initdata prom_opal_align; +static int __initdata prom_rtas_start_cpu; +static u64 __initdata prom_rtas_data; +static u64 __initdata prom_rtas_entry; + +/* XXX Don't change this structure without updating opal-takeover.S */ +static struct opal_secondary_data { + s64 ack; /* 0 */ + u64 go; /* 8 */ + struct opal_takeover_args args; /* 16 */ +} opal_secondary_data; + +extern char opal_secondary_entry; + +static void prom_query_opal(void) +{ + long rc; + + prom_printf("Querying for OPAL presence... "); + rc = opal_query_takeover(&RELOC(prom_opal_size), + &RELOC(prom_opal_align)); + prom_debug("(rc = %ld) ", rc); + if (rc != 0) { + prom_printf("not there.\n"); + return; + } + RELOC(of_platform) = PLATFORM_OPAL; + prom_printf(" there !\n"); + prom_debug(" opal_size = 0x%lx\n", RELOC(prom_opal_size)); + prom_debug(" opal_align = 0x%lx\n", RELOC(prom_opal_align)); + if (RELOC(prom_opal_align) < 0x10000) + RELOC(prom_opal_align) = 0x10000; +} + +static int prom_rtas_call(int token, int nargs, int nret, int *outputs, ...) +{ + struct rtas_args rtas_args; + va_list list; + int i; + + rtas_args.token = token; + rtas_args.nargs = nargs; + rtas_args.nret = nret; + rtas_args.rets = (rtas_arg_t *)&(rtas_args.args[nargs]); + va_start(list, outputs); + for (i = 0; i < nargs; ++i) + rtas_args.args[i] = va_arg(list, rtas_arg_t); + va_end(list); + + for (i = 0; i < nret; ++i) + rtas_args.rets[i] = 0; + + opal_enter_rtas(&rtas_args, RELOC(prom_rtas_data), + RELOC(prom_rtas_entry)); + + if (nret > 1 && outputs != NULL) + for (i = 0; i < nret-1; ++i) + outputs[i] = rtas_args.rets[i+1]; + return (nret > 0)? rtas_args.rets[0]: 0; +} + +static void __init prom_opal_hold_cpus(void) +{ + int i, cnt, cpu, rc; + long j; + phandle node; + char type[64]; + u32 servers[8]; + struct prom_t *_prom = &RELOC(prom); + void *entry = (unsigned long *)&RELOC(opal_secondary_entry); + struct opal_secondary_data *data = &RELOC(opal_secondary_data); + + prom_debug("prom_opal_hold_cpus: start...\n"); + prom_debug(" - entry = 0x%x\n", entry); + prom_debug(" - data = 0x%x\n", data); + + data->ack = -1; + data->go = 0; + + /* look for cpus */ + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("cpu")) != 0) + continue; + + /* Skip non-configured cpus. */ + if (prom_getprop(node, "status", type, sizeof(type)) > 0) + if (strcmp(type, RELOC("okay")) != 0) + continue; + + cnt = prom_getprop(node, "ibm,ppc-interrupt-server#s", servers, + sizeof(servers)); + if (cnt == PROM_ERROR) + break; + cnt >>= 2; + for (i = 0; i < cnt; i++) { + cpu = servers[i]; + prom_debug("CPU %d ... ", cpu); + if (cpu == _prom->cpu) { + prom_debug("booted !\n"); + continue; + } + prom_debug("starting ... "); + + /* Init the acknowledge var which will be reset by + * the secondary cpu when it awakens from its OF + * spinloop. + */ + data->ack = -1; + rc = prom_rtas_call(RELOC(prom_rtas_start_cpu), 3, 1, + NULL, cpu, entry, data); + prom_debug("rtas rc=%d ...", rc); + + for (j = 0; j < 100000000 && data->ack == -1; j++) { + HMT_low(); + mb(); + } + HMT_medium(); + if (data->ack != -1) + prom_debug("done, PIR=0x%x\n", data->ack); + else + prom_debug("timeout !\n"); + } + } + prom_debug("prom_opal_hold_cpus: end...\n"); +} + +static void prom_opal_takeover(void) +{ + struct opal_secondary_data *data = &RELOC(opal_secondary_data); + struct opal_takeover_args *args = &data->args; + u64 align = RELOC(prom_opal_align); + u64 top_addr, opal_addr; + + args->k_image = (u64)RELOC(_stext); + args->k_size = _end - _stext; + args->k_entry = 0; + args->k_entry2 = 0x60; + + top_addr = _ALIGN_UP(args->k_size, align); + + if (RELOC(prom_initrd_start) != 0) { + args->rd_image = RELOC(prom_initrd_start); + args->rd_size = RELOC(prom_initrd_end) - args->rd_image; + args->rd_loc = top_addr; + top_addr = _ALIGN_UP(args->rd_loc + args->rd_size, align); + } + + /* Pickup an address for the HAL. We want to go really high + * up to avoid problem with future kexecs. On the other hand + * we don't want to be all over the TCEs on P5IOC2 machines + * which are going to be up there too. We assume the machine + * has plenty of memory, and we ask for the HAL for now to + * be just below the 1G point, or above the initrd + */ + opal_addr = _ALIGN_DOWN(0x40000000 - RELOC(prom_opal_size), align); + if (opal_addr < top_addr) + opal_addr = top_addr; + args->hal_addr = opal_addr; + + prom_debug(" k_image = 0x%lx\n", args->k_image); + prom_debug(" k_size = 0x%lx\n", args->k_size); + prom_debug(" k_entry = 0x%lx\n", args->k_entry); + prom_debug(" k_entry2 = 0x%lx\n", args->k_entry2); + prom_debug(" hal_addr = 0x%lx\n", args->hal_addr); + prom_debug(" rd_image = 0x%lx\n", args->rd_image); + prom_debug(" rd_size = 0x%lx\n", args->rd_size); + prom_debug(" rd_loc = 0x%lx\n", args->rd_loc); + prom_printf("Performing OPAL takeover,this can take a few minutes..\n"); + prom_close_stdin(); + mb(); + data->go = 1; + for (;;) + opal_do_takeover(args); +} +#endif /* CONFIG_PPC_POWERNV */ /* * Allocate room for and instantiate RTAS @@ -1326,6 +1517,12 @@ static void __init prom_instantiate_rtas(void) prom_setprop(rtas_node, "/rtas", "linux,rtas-entry", &entry, sizeof(entry)); +#ifdef CONFIG_PPC_POWERNV + /* PowerVN takeover hack */ + RELOC(prom_rtas_data) = base; + RELOC(prom_rtas_entry) = entry; + prom_getprop(rtas_node, "start-cpu", &RELOC(prom_rtas_start_cpu), 4); +#endif prom_debug("rtas base = 0x%x\n", base); prom_debug("rtas entry = 0x%x\n", entry); prom_debug("rtas size = 0x%x\n", (long)size); @@ -1543,7 +1740,7 @@ static void __init prom_hold_cpus(void) *acknowledge = (unsigned long)-1; if (reg != _prom->cpu) { - /* Primary Thread of non-boot cpu */ + /* Primary Thread of non-boot cpu or any thread */ prom_printf("starting cpu hw idx %lu... ", reg); call_prom("start-cpu", 3, 0, node, secondary_hold, reg); @@ -1652,15 +1849,6 @@ static void __init prom_init_stdout(void) prom_setprop(val, path, "linux,boot-display", NULL, 0); } -static void __init prom_close_stdin(void) -{ - struct prom_t *_prom = &RELOC(prom); - ihandle val; - - if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0) - call_prom("close", 1, 0, val); -} - static int __init prom_find_machine_type(void) { struct prom_t *_prom = &RELOC(prom); @@ -2504,6 +2692,7 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4) #endif /* CONFIG_BLK_DEV_INITRD */ } + /* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. @@ -2565,7 +2754,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ prom_check_initrd(r3, r4); -#ifdef CONFIG_PPC_PSERIES +#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) /* * On pSeries, inform the firmware about our capabilities */ @@ -2611,14 +2800,30 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, #endif /* - * On non-powermacs, try to instantiate RTAS and puts all CPUs - * in spin-loops. PowerMacs don't have a working RTAS and use - * a different way to spin CPUs + * On non-powermacs, try to instantiate RTAS. PowerMacs don't + * have a usable RTAS implementation. */ - if (RELOC(of_platform) != PLATFORM_POWERMAC) { + if (RELOC(of_platform) != PLATFORM_POWERMAC) prom_instantiate_rtas(); - prom_hold_cpus(); + +#ifdef CONFIG_PPC_POWERNV + /* Detect HAL and try instanciating it & doing takeover */ + if (RELOC(of_platform) == PLATFORM_PSERIES_LPAR) { + prom_query_opal(); + if (RELOC(of_platform) == PLATFORM_OPAL) { + prom_opal_hold_cpus(); + prom_opal_takeover(); + } } +#endif + + /* + * On non-powermacs, put all CPUs in spin-loops. + * + * PowerMacs use a different mechanism to spin CPUs + */ + if (RELOC(of_platform) != PLATFORM_POWERMAC) + prom_hold_cpus(); /* * Fill in some infos for use by the kernel later on diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index 9f82f4937892..20af6aada517 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh @@ -20,7 +20,8 @@ WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush _end enter_prom memcpy memset reloc_offset __secondary_hold __secondary_hold_acknowledge __secondary_hold_spinloop __start strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 -reloc_got2 kernstart_addr memstart_addr linux_banner" +reloc_got2 kernstart_addr memstart_addr linux_banner _stext +opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry" NM="$1" OBJ="$2" diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 1c4325056b85..497133027ae5 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -1,2 +1,2 @@ -obj-y += setup.o +obj-y += setup.o opal-takeover.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/powerpc/platforms/powernv/opal-takeover.S b/arch/powerpc/platforms/powernv/opal-takeover.S new file mode 100644 index 000000000000..77b48b2b9309 --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-takeover.S @@ -0,0 +1,140 @@ +/* + * PowerNV OPAL takeover assembly code, for use by prom_init.c + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#define STK_PARAM(i) (48 + ((i)-3)*8) + +#define H_HAL_TAKEOVER 0x5124 +#define H_HAL_TAKEOVER_QUERY_MAGIC -1 + + .text +_GLOBAL(opal_query_takeover) + mfcr r0 + stw r0,8(r1) + std r3,STK_PARAM(r3)(r1) + std r4,STK_PARAM(r4)(r1) + li r3,H_HAL_TAKEOVER + li r4,H_HAL_TAKEOVER_QUERY_MAGIC + HVSC + ld r10,STK_PARAM(r3)(r1) + std r4,0(r10) + ld r10,STK_PARAM(r4)(r1) + std r5,0(r10) + lwz r0,8(r1) + mtcrf 0xff,r0 + blr + +_GLOBAL(opal_do_takeover) + mfcr r0 + stw r0,8(r1) + mflr r0 + std r0,16(r1) + bl __opal_do_takeover + ld r0,16(r1) + mtlr r0 + lwz r0,8(r1) + mtcrf 0xff,r0 + blr + +__opal_do_takeover: + ld r4,0(r3) + ld r5,0x8(r3) + ld r6,0x10(r3) + ld r7,0x18(r3) + ld r8,0x20(r3) + ld r9,0x28(r3) + ld r10,0x30(r3) + ld r11,0x38(r3) + li r3,H_HAL_TAKEOVER + HVSC + blr + + .globl opal_secondary_entry +opal_secondary_entry: + mr r31,r3 + mfmsr r11 + li r12,(MSR_SF | MSR_ISF)@highest + sldi r12,r12,48 + or r11,r11,r12 + mtmsrd r11 + isync + mfspr r4,SPRN_PIR + std r4,0(r3) +1: HMT_LOW + ld r4,8(r3) + cmpli cr0,r4,0 + beq 1b + HMT_MEDIUM +1: addi r3,r31,16 + bl __opal_do_takeover + b 1b + +_GLOBAL(opal_enter_rtas) + mflr r0 + std r0,16(r1) + stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ + + /* Because PROM is running in 32b mode, it clobbers the high order half + * of all registers that it saves. We therefore save those registers + * PROM might touch to the stack. (r0, r3-r13 are caller saved) + */ + SAVE_GPR(2, r1) + SAVE_GPR(13, r1) + SAVE_8GPRS(14, r1) + SAVE_10GPRS(22, r1) + mfcr r10 + mfmsr r11 + std r10,_CCR(r1) + std r11,_MSR(r1) + + /* Get the PROM entrypoint */ + mtlr r5 + + /* Switch MSR to 32 bits mode + */ + li r12,1 + rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) + andc r11,r11,r12 + li r12,1 + rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) + andc r11,r11,r12 + mtmsrd r11 + isync + + /* Enter RTAS here... */ + blrl + + /* Just make sure that r1 top 32 bits didn't get + * corrupt by OF + */ + rldicl r1,r1,0,32 + + /* Restore the MSR (back to 64 bits) */ + ld r0,_MSR(r1) + MTMSRD(r0) + isync + + /* Restore other registers */ + REST_GPR(2, r1) + REST_GPR(13, r1) + REST_8GPRS(14, r1) + REST_10GPRS(22, r1) + ld r4,_CCR(r1) + mtcr r4 + + addi r1,r1,PROM_FRAME_SIZE + ld r0,16(r1) + mtlr r0 + blr From 817c21ad9a1f00926f080265493923ada3458c63 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:56 +0000 Subject: [PATCH 0420/1596] powerpc/powernv: Get kernel command line accross OPAL takeover We stash it in boot_command_line which isn't in BSS and so won't be overwritten. We then use that as a default cmd_line before we walk the device-tree. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/prom.c | 7 +++++++ arch/powerpc/kernel/prom_init.c | 4 ++++ arch/powerpc/kernel/prom_init_check.sh | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 174e1e96175e..7b90c564e932 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -712,6 +712,13 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); #endif + /* Pre-initialize the cmd_line with the content of boot_commmand_line, + * which will be empty except when the content of the variable has + * been overriden by a bootloading mechanism. This happens typically + * with HAL takeover + */ + strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); + /* Retrieve various informations from the /chosen node of the * device-tree, including the platform type, initrd location and * size, TCE reserve, and more ... diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 9369287aa8c2..e3f390427216 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1449,6 +1449,10 @@ static void prom_opal_takeover(void) opal_addr = top_addr; args->hal_addr = opal_addr; + /* Copy the command line to the kernel image */ + strlcpy(RELOC(boot_command_line), RELOC(prom_cmd_line), + COMMAND_LINE_SIZE); + prom_debug(" k_image = 0x%lx\n", args->k_image); prom_debug(" k_size = 0x%lx\n", args->k_size); prom_debug(" k_entry = 0x%lx\n", args->k_entry); diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index 20af6aada517..70f4286eaa7a 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh @@ -21,7 +21,8 @@ _end enter_prom memcpy memset reloc_offset __secondary_hold __secondary_hold_acknowledge __secondary_hold_spinloop __start strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 reloc_got2 kernstart_addr memstart_addr linux_banner _stext -opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry" +opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry +boot_command_line" NM="$1" OBJ="$2" From 14a43e69ed257a1fadadf9fea2c05adb1686419f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:57 +0000 Subject: [PATCH 0421/1596] powerpc/powernv: Basic support for OPAL Add definition of OPAL interfaces along with the wrappers to call into OPAL runtime and the early device-tree parsing hook to locate the OPAL runtime firmware. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/firmware.h | 10 + arch/powerpc/include/asm/opal.h | 382 +++++++++++++++++- arch/powerpc/kernel/prom.c | 7 + arch/powerpc/platforms/powernv/Kconfig | 9 +- arch/powerpc/platforms/powernv/Makefile | 2 +- .../powerpc/platforms/powernv/opal-wrappers.S | 101 +++++ arch/powerpc/platforms/powernv/opal.c | 154 +++++++ arch/powerpc/platforms/powernv/setup.c | 6 + arch/powerpc/platforms/powernv/smp.c | 25 +- 9 files changed, 691 insertions(+), 5 deletions(-) create mode 100644 arch/powerpc/platforms/powernv/opal-wrappers.S create mode 100644 arch/powerpc/platforms/powernv/opal.c diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index 3a6c586c4e40..14db29b18d0e 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -48,6 +48,8 @@ #define FW_FEATURE_CMO ASM_CONST(0x0000000002000000) #define FW_FEATURE_VPHN ASM_CONST(0x0000000004000000) #define FW_FEATURE_XCMO ASM_CONST(0x0000000008000000) +#define FW_FEATURE_OPAL ASM_CONST(0x0000000010000000) +#define FW_FEATURE_OPALv2 ASM_CONST(0x0000000020000000) #ifndef __ASSEMBLY__ @@ -65,6 +67,8 @@ enum { FW_FEATURE_PSERIES_ALWAYS = 0, FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, + FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2, + FW_FEATURE_POWERNV_ALWAYS = 0, FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1, FW_FEATURE_PS3_ALWAYS = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1, FW_FEATURE_CELLEB_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_BEAT, @@ -78,6 +82,9 @@ enum { #ifdef CONFIG_PPC_ISERIES FW_FEATURE_ISERIES_POSSIBLE | #endif +#ifdef CONFIG_PPC_POWERNV + FW_FEATURE_POWERNV_POSSIBLE | +#endif #ifdef CONFIG_PPC_PS3 FW_FEATURE_PS3_POSSIBLE | #endif @@ -95,6 +102,9 @@ enum { #ifdef CONFIG_PPC_ISERIES FW_FEATURE_ISERIES_ALWAYS & #endif +#ifdef CONFIG_PPC_POWERNV + FW_FEATURE_POWERNV_ALWAYS & +#endif #ifdef CONFIG_PPC_PS3 FW_FEATURE_PS3_ALWAYS & #endif diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index ecdb283f8b7c..c7a3202d10a0 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -37,14 +37,394 @@ extern long opal_query_takeover(u64 *hal_size, u64 *hal_align); extern long opal_do_takeover(struct opal_takeover_args *args); +struct rtas_args; extern int opal_enter_rtas(struct rtas_args *args, unsigned long data, unsigned long entry); - #endif /* __ASSEMBLY__ */ /****** OPAL APIs ******/ +/* Return codes */ +#define OPAL_SUCCESS 0 +#define OPAL_PARAMETER -1 +#define OPAL_BUSY -2 +#define OPAL_PARTIAL -3 +#define OPAL_CONSTRAINED -4 +#define OPAL_CLOSED -5 +#define OPAL_HARDWARE -6 +#define OPAL_UNSUPPORTED -7 +#define OPAL_PERMISSION -8 +#define OPAL_NO_MEM -9 +#define OPAL_RESOURCE -10 +#define OPAL_INTERNAL_ERROR -11 +#define OPAL_BUSY_EVENT -12 +#define OPAL_HARDWARE_FROZEN -13 + +/* API Tokens (in r0) */ +#define OPAL_CONSOLE_WRITE 1 +#define OPAL_CONSOLE_READ 2 +#define OPAL_RTC_READ 3 +#define OPAL_RTC_WRITE 4 +#define OPAL_CEC_POWER_DOWN 5 +#define OPAL_CEC_REBOOT 6 +#define OPAL_READ_NVRAM 7 +#define OPAL_WRITE_NVRAM 8 +#define OPAL_HANDLE_INTERRUPT 9 +#define OPAL_POLL_EVENTS 10 +#define OPAL_PCI_SET_HUB_TCE_MEMORY 11 +#define OPAL_PCI_SET_PHB_TCE_MEMORY 12 +#define OPAL_PCI_CONFIG_READ_BYTE 13 +#define OPAL_PCI_CONFIG_READ_HALF_WORD 14 +#define OPAL_PCI_CONFIG_READ_WORD 15 +#define OPAL_PCI_CONFIG_WRITE_BYTE 16 +#define OPAL_PCI_CONFIG_WRITE_HALF_WORD 17 +#define OPAL_PCI_CONFIG_WRITE_WORD 18 +#define OPAL_SET_XIVE 19 +#define OPAL_GET_XIVE 20 +#define OPAL_GET_COMPLETION_TOKEN_STATUS 21 /* obsolete */ +#define OPAL_REGISTER_OPAL_EXCEPTION_HANDLER 22 +#define OPAL_PCI_EEH_FREEZE_STATUS 23 +#define OPAL_PCI_SHPC 24 +#define OPAL_CONSOLE_WRITE_BUFFER_SPACE 25 +#define OPAL_PCI_EEH_FREEZE_CLEAR 26 +#define OPAL_PCI_PHB_MMIO_ENABLE 27 +#define OPAL_PCI_SET_PHB_MEM_WINDOW 28 +#define OPAL_PCI_MAP_PE_MMIO_WINDOW 29 +#define OPAL_PCI_SET_PHB_TABLE_MEMORY 30 +#define OPAL_PCI_SET_PE 31 +#define OPAL_PCI_SET_PELTV 32 +#define OPAL_PCI_SET_MVE 33 +#define OPAL_PCI_SET_MVE_ENABLE 34 +#define OPAL_PCI_GET_XIVE_REISSUE 35 +#define OPAL_PCI_SET_XIVE_REISSUE 36 +#define OPAL_PCI_SET_XIVE_PE 37 +#define OPAL_GET_XIVE_SOURCE 38 +#define OPAL_GET_MSI_32 39 +#define OPAL_GET_MSI_64 40 +#define OPAL_START_CPU 41 +#define OPAL_QUERY_CPU_STATUS 42 +#define OPAL_WRITE_OPPANEL 43 +#define OPAL_PCI_MAP_PE_DMA_WINDOW 44 +#define OPAL_PCI_MAP_PE_DMA_WINDOW_REAL 45 +#define OPAL_PCI_RESET 49 + +#ifndef __ASSEMBLY__ + +/* Other enums */ +enum OpalVendorApiTokens { + OPAL_START_VENDOR_API_RANGE = 1000, OPAL_END_VENDOR_API_RANGE = 1999 +}; +enum OpalFreezeState { + OPAL_EEH_STOPPED_NOT_FROZEN = 0, + OPAL_EEH_STOPPED_MMIO_FREEZE = 1, + OPAL_EEH_STOPPED_DMA_FREEZE = 2, + OPAL_EEH_STOPPED_MMIO_DMA_FREEZE = 3, + OPAL_EEH_STOPPED_RESET = 4, + OPAL_EEH_STOPPED_TEMP_UNAVAIL = 5, + OPAL_EEH_STOPPED_PERM_UNAVAIL = 6 +}; +enum OpalEehFreezeActionToken { + OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO = 1, + OPAL_EEH_ACTION_CLEAR_FREEZE_DMA = 2, + OPAL_EEH_ACTION_CLEAR_FREEZE_ALL = 3 +}; +enum OpalPciStatusToken { + OPAL_EEH_PHB_NO_ERROR = 0, + OPAL_EEH_PHB_FATAL = 1, + OPAL_EEH_PHB_RECOVERABLE = 2, + OPAL_EEH_PHB_BUS_ERROR = 3, + OPAL_EEH_PCI_NO_DEVSEL = 4, + OPAL_EEH_PCI_TA = 5, + OPAL_EEH_PCIEX_UR = 6, + OPAL_EEH_PCIEX_CA = 7, + OPAL_EEH_PCI_MMIO_ERROR = 8, + OPAL_EEH_PCI_DMA_ERROR = 9 +}; +enum OpalShpcAction { + OPAL_SHPC_GET_LINK_STATE = 0, + OPAL_SHPC_GET_SLOT_STATE = 1 +}; +enum OpalShpcLinkState { + OPAL_SHPC_LINK_DOWN = 0, + OPAL_SHPC_LINK_UP = 1 +}; +enum OpalMmioWindowType { + OPAL_M32_WINDOW_TYPE = 1, + OPAL_M64_WINDOW_TYPE = 2, + OPAL_IO_WINDOW_TYPE = 3 +}; +enum OpalShpcSlotState { + OPAL_SHPC_DEV_NOT_PRESENT = 0, + OPAL_SHPC_DEV_PRESENT = 1 +}; +enum OpalExceptionHandler { + OPAL_MACHINE_CHECK_HANDLER = 1, + OPAL_HYPERVISOR_MAINTENANCE_HANDLER = 2, + OPAL_SOFTPATCH_HANDLER = 3 +}; +enum OpalPendingState { + OPAL_EVENT_OPAL_INTERNAL = 0x1, + OPAL_EVENT_NVRAM = 0x2, + OPAL_EVENT_RTC = 0x4, + OPAL_EVENT_CONSOLE_OUTPUT = 0x8, + OPAL_EVENT_CONSOLE_INPUT = 0x10 +}; + +/* Machine check related definitions */ +enum OpalMCE_Version { + OpalMCE_V1 = 1, +}; + +enum OpalMCE_Severity { + OpalMCE_SEV_NO_ERROR = 0, + OpalMCE_SEV_WARNING = 1, + OpalMCE_SEV_ERROR_SYNC = 2, + OpalMCE_SEV_FATAL = 3, +}; + +enum OpalMCE_Disposition { + OpalMCE_DISPOSITION_RECOVERED = 0, + OpalMCE_DISPOSITION_NOT_RECOVERED = 1, +}; + +enum OpalMCE_Initiator { + OpalMCE_INITIATOR_UNKNOWN = 0, + OpalMCE_INITIATOR_CPU = 1, +}; + +enum OpalMCE_ErrorType { + OpalMCE_ERROR_TYPE_UNKNOWN = 0, + OpalMCE_ERROR_TYPE_UE = 1, + OpalMCE_ERROR_TYPE_SLB = 2, + OpalMCE_ERROR_TYPE_ERAT = 3, + OpalMCE_ERROR_TYPE_TLB = 4, +}; + +enum OpalMCE_UeErrorType { + OpalMCE_UE_ERROR_INDETERMINATE = 0, + OpalMCE_UE_ERROR_IFETCH = 1, + OpalMCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH = 2, + OpalMCE_UE_ERROR_LOAD_STORE = 3, + OpalMCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 4, +}; + +enum OpalMCE_SlbErrorType { + OpalMCE_SLB_ERROR_INDETERMINATE = 0, + OpalMCE_SLB_ERROR_PARITY = 1, + OpalMCE_SLB_ERROR_MULTIHIT = 2, +}; + +enum OpalMCE_EratErrorType { + OpalMCE_ERAT_ERROR_INDETERMINATE = 0, + OpalMCE_ERAT_ERROR_PARITY = 1, + OpalMCE_ERAT_ERROR_MULTIHIT = 2, +}; + +enum OpalMCE_TlbErrorType { + OpalMCE_TLB_ERROR_INDETERMINATE = 0, + OpalMCE_TLB_ERROR_PARITY = 1, + OpalMCE_TLB_ERROR_MULTIHIT = 2, +}; + +enum OpalThreadStatus { + OPAL_THREAD_INACTIVE = 0x0, + OPAL_THREAD_STARTED = 0x1 +}; + +enum OpalPciBusCompare { + OpalPciBusAny = 0, /* Any bus number match */ + OpalPciBus3Bits = 2, /* Match top 3 bits of bus number */ + OpalPciBus4Bits = 3, /* Match top 4 bits of bus number */ + OpalPciBus5Bits = 4, /* Match top 5 bits of bus number */ + OpalPciBus6Bits = 5, /* Match top 6 bits of bus number */ + OpalPciBus7Bits = 6, /* Match top 7 bits of bus number */ + OpalPciBusAll = 7, /* Match bus number exactly */ +}; + +enum OpalDeviceCompare { + OPAL_IGNORE_RID_DEVICE_NUMBER = 0, + OPAL_COMPARE_RID_DEVICE_NUMBER = 1 +}; + +enum OpalFuncCompare { + OPAL_IGNORE_RID_FUNCTION_NUMBER = 0, + OPAL_COMPARE_RID_FUNCTION_NUMBER = 1 +}; + +enum OpalPeAction { + OPAL_UNMAP_PE = 0, + OPAL_MAP_PE = 1 +}; + +enum OpalPciResetAndReinitScope { + OPAL_PHB_COMPLETE = 1, OPAL_PCI_LINK = 2, OPAL_PHB_ERROR = 3, + OPAL_PCI_HOT_RESET = 4, OPAL_PCI_FUNDAMENTAL_RESET = 5, + OPAL_PCI_IODA_RESET = 6, +}; + +enum OpalPciResetState { OPAL_DEASSERT_RESET = 0, OPAL_ASSERT_RESET = 1 }; + +struct opal_machine_check_event { + enum OpalMCE_Version version:8; /* 0x00 */ + uint8_t in_use; /* 0x01 */ + enum OpalMCE_Severity severity:8; /* 0x02 */ + enum OpalMCE_Initiator initiator:8; /* 0x03 */ + enum OpalMCE_ErrorType error_type:8; /* 0x04 */ + enum OpalMCE_Disposition disposition:8; /* 0x05 */ + uint8_t reserved_1[2]; /* 0x06 */ + uint64_t gpr3; /* 0x08 */ + uint64_t srr0; /* 0x10 */ + uint64_t srr1; /* 0x18 */ + union { /* 0x20 */ + struct { + enum OpalMCE_UeErrorType ue_error_type:8; + uint8_t effective_address_provided; + uint8_t physical_address_provided; + uint8_t reserved_1[5]; + uint64_t effective_address; + uint64_t physical_address; + uint8_t reserved_2[8]; + } ue_error; + + struct { + enum OpalMCE_SlbErrorType slb_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } slb_error; + + struct { + enum OpalMCE_EratErrorType erat_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } erat_error; + + struct { + enum OpalMCE_TlbErrorType tlb_error_type:8; + uint8_t effective_address_provided; + uint8_t reserved_1[6]; + uint64_t effective_address; + uint8_t reserved_2[16]; + } tlb_error; + } u; +}; + +typedef struct oppanel_line { + /* XXX */ +} oppanel_line_t; + +/* API functions */ +int64_t opal_console_write(int64_t term_number, int64_t *length, + const uint8_t *buffer); +int64_t opal_console_read(int64_t term_number, int64_t *length, + uint8_t *buffer); +int64_t opal_console_write_buffer_space(int64_t term_number, + int64_t *length); +int64_t opal_rtc_read(uint32_t *year_month_day, + uint64_t *hour_minute_second_millisecond); +int64_t opal_rtc_write(uint32_t year_month_day, + uint64_t hour_minute_second_millisecond); +int64_t opal_cec_power_down(uint64_t request); +int64_t opal_cec_reboot(void); +int64_t opal_read_nvram(uint64_t buffer, uint64_t size, uint64_t offset); +int64_t opal_write_nvram(uint64_t buffer, uint64_t size, uint64_t offset); +int64_t opal_handle_interrupt(uint64_t isn, uint64_t *outstanding_event_mask); +int64_t opal_poll_events(uint64_t *outstanding_event_mask); +int64_t opal_pci_set_hub_tce_memory(uint64_t hub_id, uint64_t tce_mem_addr, + uint64_t tce_mem_size); +int64_t opal_pci_set_phb_tce_memory(uint64_t phb_id, uint64_t tce_mem_addr, + uint64_t tce_mem_size); +int64_t opal_pci_config_read_byte(uint64_t phb_id, uint64_t bus_dev_func, + uint64_t offset, uint8_t *data); +int64_t opal_pci_config_read_half_word(uint64_t phb_id, uint64_t bus_dev_func, + uint64_t offset, uint16_t *data); +int64_t opal_pci_config_read_word(uint64_t phb_id, uint64_t bus_dev_func, + uint64_t offset, uint32_t *data); +int64_t opal_pci_config_write_byte(uint64_t phb_id, uint64_t bus_dev_func, + uint64_t offset, uint8_t data); +int64_t opal_pci_config_write_half_word(uint64_t phb_id, uint64_t bus_dev_func, + uint64_t offset, uint16_t data); +int64_t opal_pci_config_write_word(uint64_t phb_id, uint64_t bus_dev_func, + uint64_t offset, uint32_t data); +int64_t opal_set_xive(uint32_t isn, uint16_t server, uint8_t priority); +int64_t opal_get_xive(uint32_t isn, uint16_t *server, uint8_t *priority); +int64_t opal_register_exception_handler(uint64_t opal_exception, + uint64_t handler_address, + uint64_t glue_cache_line); +int64_t opal_pci_eeh_freeze_status(uint64_t phb_id, uint64_t pe_number, + uint8_t *freeze_state, + uint16_t *pci_error_type, + uint64_t *phb_status); +int64_t opal_pci_eeh_freeze_clear(uint64_t phb_id, uint64_t pe_number, + uint64_t eeh_action_token); +int64_t opal_pci_shpc(uint64_t phb_id, uint64_t shpc_action, uint8_t *state); + + + +int64_t opal_pci_phb_mmio_enable(uint64_t phb_id, uint16_t window_type, + uint16_t window_num, uint16_t enable); +int64_t opal_pci_set_phb_mem_window(uint64_t phb_id, uint16_t window_type, + uint16_t window_num, + uint64_t starting_real_address, + uint64_t starting_pci_address, + uint16_t segment_size); +int64_t opal_pci_map_pe_mmio_window(uint64_t phb_id, uint16_t pe_number, + uint16_t window_type, uint16_t window_num, + uint16_t segment_num); +int64_t opal_pci_set_phb_table_memory(uint64_t phb_id, uint64_t rtt_addr, + uint64_t ivt_addr, uint64_t ivt_len, + uint64_t reject_array_addr, + uint64_t peltv_addr); +int64_t opal_pci_set_pe(uint64_t phb_id, uint64_t pe_number, uint64_t bus_dev_func, + uint8_t bus_compare, uint8_t dev_compare, uint8_t func_compare, + uint8_t pe_action); +int64_t opal_pci_set_peltv(uint64_t phb_id, uint32_t parent_pe, uint32_t child_pe, + uint8_t state); +int64_t opal_pci_set_mve(uint64_t phb_id, uint32_t mve_number, uint32_t pe_number); +int64_t opal_pci_set_mve_enable(uint64_t phb_id, uint32_t mve_number, + uint32_t state); +int64_t opal_pci_get_xive_reissue(uint64_t phb_id, uint32_t xive_number, + uint8_t *p_bit, uint8_t *q_bit); +int64_t opal_pci_set_xive_reissue(uint64_t phb_id, uint32_t xive_number, + uint8_t p_bit, uint8_t q_bit); +int64_t opal_pci_set_xive_pe(uint64_t phb_id, uint32_t pe_number, + uint32_t xive_num); +int64_t opal_get_xive_source(uint64_t phb_id, uint32_t xive_num, + int32_t *interrupt_source_number); +int64_t opal_get_msi_32(uint64_t phb_id, uint32_t mve_number, uint32_t xive_num, + uint8_t msi_range, uint32_t *msi_address, + uint32_t *message_data); +int64_t opal_get_msi_64(uint64_t phb_id, uint32_t mve_number, + uint32_t xive_num, uint8_t msi_range, + uint64_t *msi_address, uint32_t *message_data); +int64_t opal_start_cpu(uint64_t thread_number, uint64_t start_address); +int64_t opal_query_cpu_status(uint64_t thread_number, uint8_t *thread_status); +int64_t opal_write_oppanel(oppanel_line_t *lines, uint64_t num_lines); +int64_t opal_pci_map_pe_dma_window(uint64_t phb_id, uint16_t pe_number, uint16_t window_id, + uint16_t tce_levels, uint64_t tce_table_addr, + uint64_t tce_table_size, uint64_t tce_page_size); +int64_t opal_pci_map_pe_dma_window_real(uint64_t phb_id, uint16_t pe_number, + uint16_t dma_window_number, uint64_t pci_start_addr, + uint64_t pci_mem_size); +int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope, uint8_t assert_state); + +/* Internal functions */ +extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data); + +extern int opal_get_chars(uint32_t vtermno, char *buf, int count); +extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); + +extern void hvc_opal_init_early(void); + +/* Internal functions */ +extern int early_init_dt_scan_opal(unsigned long node, const char *uname, + int depth, void *data); + +#endif /* __ASSEMBLY__ */ #endif /* __OPAL_H */ diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 7b90c564e932..831a201e03d2 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -54,6 +54,8 @@ #include #include #include +#include + #include #ifdef DEBUG @@ -707,6 +709,11 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_rtas, NULL); #endif +#ifdef CONFIG_PPC_POWERNV + /* Some machines might need OPAL info for debugging, grab it now. */ + of_scan_flat_dt(early_init_dt_scan_opal, NULL); +#endif + #ifdef CONFIG_PHYP_DUMP /* scan tree to see if dump occurred during last boot */ of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig index 24700e8df19c..74fea5c21839 100644 --- a/arch/powerpc/platforms/powernv/Kconfig +++ b/arch/powerpc/platforms/powernv/Kconfig @@ -1,11 +1,16 @@ config PPC_POWERNV depends on PPC64 && PPC_BOOK3S bool "IBM PowerNV (Non-Virtualized) platform support" - select PPC_RTAS select PPC_NATIVE select PPC_XICS select PPC_ICP_NATIVE - select PPC_ICS_RTAS select PPC_P7_NAP select PPC_PCI_CHOICE if EMBEDDED default y + +config PPC_POWERNV_RTAS + depends on PPC_POWERNV + bool "Support for RTAS based PowerNV platforms such as BML" + default y + select PPC_ICS_RTAS + select PPC_RTAS diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 497133027ae5..8f69c0db612c 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -1,2 +1,2 @@ -obj-y += setup.o opal-takeover.o +obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S new file mode 100644 index 000000000000..4a3f46d8533e --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -0,0 +1,101 @@ +/* + * PowerNV OPAL API wrappers + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +/* TODO: + * + * - Trace irqs in/off (needs saving/restoring all args, argh...) + * - Get r11 feed up by Dave so I can have better register usage + */ +#define OPAL_CALL(name, token) \ + _GLOBAL(name); \ + mflr r0; \ + mfcr r12; \ + std r0,16(r1); \ + std r12,8(r1); \ + std r1,PACAR1(r13); \ + li r0,0; \ + mfmsr r12; \ + ori r0,r0,MSR_EE; \ + std r12,PACASAVEDMSR(r13); \ + andc r12,r12,r0; \ + mtmsrd r12,1; \ + LOAD_REG_ADDR(r0,.opal_return); \ + mtlr r0; \ + li r0,MSR_DR|MSR_IR; \ + andc r12,r12,r0; \ + li r0,token; \ + mtspr SPRN_HSRR1,r12; \ + LOAD_REG_ADDR(r11,opal); \ + ld r12,8(r11); \ + ld r2,0(r11); \ + mtspr SPRN_HSRR0,r12; \ + hrfid + +_STATIC(opal_return) + ld r2,PACATOC(r13); + ld r4,8(r1); + ld r5,16(r1); + ld r6,PACASAVEDMSR(r13); + mtspr SPRN_SRR0,r5; + mtspr SPRN_SRR1,r6; + mtcr r4; + rfid + +OPAL_CALL(opal_console_write, OPAL_CONSOLE_WRITE); +OPAL_CALL(opal_console_read, OPAL_CONSOLE_READ); +OPAL_CALL(opal_console_write_buffer_space, OPAL_CONSOLE_WRITE_BUFFER_SPACE); +OPAL_CALL(opal_rtc_read, OPAL_RTC_READ); +OPAL_CALL(opal_rtc_write, OPAL_RTC_WRITE); +OPAL_CALL(opal_cec_power_down, OPAL_CEC_POWER_DOWN); +OPAL_CALL(opal_cec_reboot, OPAL_CEC_REBOOT); +OPAL_CALL(opal_read_nvram, OPAL_READ_NVRAM); +OPAL_CALL(opal_write_nvram, OPAL_WRITE_NVRAM); +OPAL_CALL(opal_handle_interrupt, OPAL_HANDLE_INTERRUPT); +OPAL_CALL(opal_poll_events, OPAL_POLL_EVENTS); +OPAL_CALL(opal_pci_set_hub_tce_memory, OPAL_PCI_SET_HUB_TCE_MEMORY); +OPAL_CALL(opal_pci_set_phb_tce_memory, OPAL_PCI_SET_PHB_TCE_MEMORY); +OPAL_CALL(opal_pci_config_read_byte, OPAL_PCI_CONFIG_READ_BYTE); +OPAL_CALL(opal_pci_config_read_half_word, OPAL_PCI_CONFIG_READ_HALF_WORD); +OPAL_CALL(opal_pci_config_read_word, OPAL_PCI_CONFIG_READ_WORD); +OPAL_CALL(opal_pci_config_write_byte, OPAL_PCI_CONFIG_WRITE_BYTE); +OPAL_CALL(opal_pci_config_write_half_word, OPAL_PCI_CONFIG_WRITE_HALF_WORD); +OPAL_CALL(opal_pci_config_write_word, OPAL_PCI_CONFIG_WRITE_WORD); +OPAL_CALL(opal_set_xive, OPAL_SET_XIVE); +OPAL_CALL(opal_get_xive, OPAL_GET_XIVE); +OPAL_CALL(opal_register_exception_handler, OPAL_REGISTER_OPAL_EXCEPTION_HANDLER); +OPAL_CALL(opal_pci_eeh_freeze_status, OPAL_PCI_EEH_FREEZE_STATUS); +OPAL_CALL(opal_pci_eeh_freeze_clear, OPAL_PCI_EEH_FREEZE_CLEAR); +OPAL_CALL(opal_pci_shpc, OPAL_PCI_SHPC); +OPAL_CALL(opal_pci_phb_mmio_enable, OPAL_PCI_PHB_MMIO_ENABLE); +OPAL_CALL(opal_pci_set_phb_mem_window, OPAL_PCI_SET_PHB_MEM_WINDOW); +OPAL_CALL(opal_pci_map_pe_mmio_window, OPAL_PCI_MAP_PE_MMIO_WINDOW); +OPAL_CALL(opal_pci_set_phb_table_memory, OPAL_PCI_SET_PHB_TABLE_MEMORY); +OPAL_CALL(opal_pci_set_pe, OPAL_PCI_SET_PE); +OPAL_CALL(opal_pci_set_peltv, OPAL_PCI_SET_PELTV); +OPAL_CALL(opal_pci_set_mve, OPAL_PCI_SET_MVE); +OPAL_CALL(opal_pci_set_mve_enable, OPAL_PCI_SET_MVE_ENABLE); +OPAL_CALL(opal_pci_get_xive_reissue, OPAL_PCI_GET_XIVE_REISSUE); +OPAL_CALL(opal_pci_set_xive_reissue, OPAL_PCI_SET_XIVE_REISSUE); +OPAL_CALL(opal_pci_set_xive_pe, OPAL_PCI_SET_XIVE_PE); +OPAL_CALL(opal_get_xive_source, OPAL_GET_XIVE_SOURCE); +OPAL_CALL(opal_get_msi_32, OPAL_GET_MSI_32); +OPAL_CALL(opal_get_msi_64, OPAL_GET_MSI_64); +OPAL_CALL(opal_start_cpu, OPAL_START_CPU); +OPAL_CALL(opal_query_cpu_status, OPAL_QUERY_CPU_STATUS); +OPAL_CALL(opal_write_oppanel, OPAL_WRITE_OPPANEL); +OPAL_CALL(opal_pci_map_pe_dma_window, OPAL_PCI_MAP_PE_DMA_WINDOW); +OPAL_CALL(opal_pci_map_pe_dma_window_real, OPAL_PCI_MAP_PE_DMA_WINDOW_REAL); +OPAL_CALL(opal_pci_reset, OPAL_PCI_RESET); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c new file mode 100644 index 000000000000..8d5510784cc2 --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal.c @@ -0,0 +1,154 @@ +/* + * PowerNV OPAL high level interfaces + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include + +#include "powernv.h" + +struct opal { + u64 base; + u64 entry; +} opal; + +static struct device_node *opal_node; +static DEFINE_SPINLOCK(opal_write_lock); + +int __init early_init_dt_scan_opal(unsigned long node, + const char *uname, int depth, void *data) +{ + const void *basep, *entryp; + unsigned long basesz, entrysz; + + if (depth != 1 || strcmp(uname, "ibm,opal") != 0) + return 0; + + basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz); + entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz); + + if (!basep || !entryp) + return 1; + + opal.base = of_read_number(basep, basesz/4); + opal.entry = of_read_number(entryp, entrysz/4); + + pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n", + opal.base, basep, basesz); + pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n", + opal.entry, entryp, entrysz); + + powerpc_firmware_features |= FW_FEATURE_OPAL; + if (of_flat_dt_is_compatible(node, "ibm,opal-v2")) { + powerpc_firmware_features |= FW_FEATURE_OPALv2; + printk("OPAL V2 detected !\n"); + } else { + printk("OPAL V1 detected !\n"); + } + + return 1; +} + +int opal_get_chars(uint32_t vtermno, char *buf, int count) +{ + s64 len, rc; + u64 evt; + + if (!opal.entry) + return 0; + opal_poll_events(&evt); + if ((evt & OPAL_EVENT_CONSOLE_INPUT) == 0) + return 0; + len = count; + rc = opal_console_read(vtermno, &len, buf); + if (rc == OPAL_SUCCESS) + return len; + return 0; +} + +int opal_put_chars(uint32_t vtermno, const char *data, int total_len) +{ + int written = 0; + s64 len, rc = OPAL_BUSY; + unsigned long flags; + u64 evt; + + if (!opal.entry) + return 0; + + /* We want put_chars to be atomic to avoid mangling of hvsi + * packets. To do that, we first test for room and return + * -EAGAIN if there isn't enough + */ + spin_lock_irqsave(&opal_write_lock, flags); + rc = opal_console_write_buffer_space(vtermno, &len); + if (rc || len < total_len) { + spin_unlock_irqrestore(&opal_write_lock, flags); + /* Closed -> drop characters */ + if (rc) + return total_len; + opal_poll_events(&evt); + return -EAGAIN; + } + + /* We still try to handle partial completions, though they + * should no longer happen. + */ + while(total_len > 0 && (rc == OPAL_BUSY || + rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) { + len = total_len; + rc = opal_console_write(vtermno, &len, data); + if (rc == OPAL_SUCCESS) { + total_len -= len; + data += len; + written += len; + } + /* This is a bit nasty but we need that for the console to + * flush when there aren't any interrupts. We will clean + * things a bit later to limit that to synchronous path + * such as the kernel console and xmon/udbg + */ + do + opal_poll_events(&evt); + while(rc == OPAL_SUCCESS && (evt & OPAL_EVENT_CONSOLE_OUTPUT)); + } + spin_unlock_irqrestore(&opal_write_lock, flags); + return written; +} + +static int __init opal_init(void) +{ + struct device_node *np, *consoles; + + opal_node = of_find_node_by_path("/ibm,opal"); + if (!opal_node) { + pr_warn("opal: Node not found\n"); + return -ENODEV; + } + if (firmware_has_feature(FW_FEATURE_OPALv2)) + consoles = of_find_node_by_path("/ibm,opal/consoles"); + else + consoles = of_node_get(opal_node); + + /* Register serial ports */ + for_each_child_of_node(consoles, np) { + if (strcmp(np->name, "serial")) + continue; + of_platform_device_create(np, NULL, NULL); + } + of_node_put(consoles); + return 0; +} +subsys_initcall(opal_init); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 569f9cc4eb04..b6e5ff85cc6f 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -74,6 +74,12 @@ static void pnv_show_cpuinfo(struct seq_file *m) if (root) model = of_get_property(root, "model", NULL); seq_printf(m, "machine\t\t: PowerNV %s\n", model); + if (firmware_has_feature(FW_FEATURE_OPALv2)) + seq_printf(m, "firmware\t: OPAL v2\n"); + else if (firmware_has_feature(FW_FEATURE_OPAL)) + seq_printf(m, "firmware\t: OPAL v1\n"); + else + seq_printf(m, "firmware\t: BML\n"); of_node_put(root); } diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index 4f4ec3797eb6..e87736685243 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "powernv.h" @@ -62,6 +63,28 @@ static int pnv_smp_cpu_bootable(unsigned int nr) return 1; } +int __devinit pnv_smp_kick_cpu(int nr) +{ + unsigned int pcpu = get_hard_smp_processor_id(nr); + unsigned long start_here = __pa(*((unsigned long *) + generic_secondary_smp_init)); + long rc; + + BUG_ON(nr < 0 || nr >= NR_CPUS); + + /* On OPAL v2 the CPU are still spinning inside OPAL itself, + * get them back now + */ + if (firmware_has_feature(FW_FEATURE_OPALv2)) { + pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n", nr, pcpu); + rc = opal_start_cpu(pcpu, start_here); + if (rc != OPAL_SUCCESS) + pr_warn("OPAL Error %ld starting CPU %d\n", + rc, nr); + } + return smp_generic_kick_cpu(nr); +} + #ifdef CONFIG_HOTPLUG_CPU static int pnv_smp_cpu_disable(void) @@ -127,7 +150,7 @@ static struct smp_ops_t pnv_smp_ops = { .message_pass = smp_muxed_ipi_message_pass, .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */ .probe = xics_smp_probe, - .kick_cpu = smp_generic_kick_cpu, + .kick_cpu = pnv_smp_kick_cpu, .setup_cpu = pnv_smp_setup_cpu, .cpu_bootable = pnv_smp_cpu_bootable, #ifdef CONFIG_HOTPLUG_CPU From 6e35d5dac0c83ebb616ff3b9c2d6155c9a9ccb86 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 18:28:01 +0000 Subject: [PATCH 0422/1596] powerpc/powernv: Add support for instanciating OPAL v2 from Open Firmware OPAL v2 is instantiated in a way similar to RTAS using Open Firmware client interface calls, and the resulting address and entry point are put in the device-tree Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/prom_init.c | 136 +++++++++++++++++++++++++++----- 1 file changed, 117 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index e3f390427216..e96f5d0d2c78 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -140,7 +140,9 @@ struct mem_map_entry { typedef u32 cell_t; -extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); +extern void __start(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, unsigned long r8, + unsigned long r9); #ifdef CONFIG_PPC64 extern int enter_prom(struct prom_args *args, unsigned long entry); @@ -1293,6 +1295,11 @@ static int __initdata prom_rtas_start_cpu; static u64 __initdata prom_rtas_data; static u64 __initdata prom_rtas_entry; +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL +static u64 __initdata prom_opal_base; +static u64 __initdata prom_opal_entry; +#endif + /* XXX Don't change this structure without updating opal-takeover.S */ static struct opal_secondary_data { s64 ack; /* 0 */ @@ -1468,6 +1475,76 @@ static void prom_opal_takeover(void) for (;;) opal_do_takeover(args); } + +/* + * Allocate room for and instantiate OPAL + */ +static void __init prom_instantiate_opal(void) +{ + phandle opal_node; + ihandle opal_inst; + u64 base, entry; + u64 size = 0, align = 0x10000; + u32 rets[2]; + + prom_debug("prom_instantiate_opal: start...\n"); + + opal_node = call_prom("finddevice", 1, 1, ADDR("/ibm,opal")); + prom_debug("opal_node: %x\n", opal_node); + if (!PHANDLE_VALID(opal_node)) + return; + + prom_getprop(opal_node, "opal-runtime-size", &size, sizeof(size)); + if (size == 0) + return; + prom_getprop(opal_node, "opal-runtime-alignment", &align, + sizeof(align)); + + base = alloc_down(size, align, 0); + if (base == 0) { + prom_printf("OPAL allocation failed !\n"); + return; + } + + opal_inst = call_prom("open", 1, 1, ADDR("/ibm,opal")); + if (!IHANDLE_VALID(opal_inst)) { + prom_printf("opening opal package failed (%x)\n", opal_inst); + return; + } + + prom_printf("instantiating opal at 0x%x...", base); + + if (call_prom_ret("call-method", 4, 3, rets, + ADDR("load-opal-runtime"), + opal_inst, + base >> 32, base & 0xffffffff) != 0 + || (rets[0] == 0 && rets[1] == 0)) { + prom_printf(" failed\n"); + return; + } + entry = (((u64)rets[0]) << 32) | rets[1]; + + prom_printf(" done\n"); + + reserve_mem(base, size); + + prom_debug("opal base = 0x%x\n", base); + prom_debug("opal align = 0x%x\n", align); + prom_debug("opal entry = 0x%x\n", entry); + prom_debug("opal size = 0x%x\n", (long)size); + + prom_setprop(opal_node, "/ibm,opal", "opal-base-address", + &base, sizeof(base)); + prom_setprop(opal_node, "/ibm,opal", "opal-entry-address", + &entry, sizeof(entry)); + +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL + RELOC(prom_opal_base) = base; + RELOC(prom_opal_entry) = entry; +#endif + prom_debug("prom_instantiate_opal: end...\n"); +} + #endif /* CONFIG_PPC_POWERNV */ /* @@ -1863,7 +1940,7 @@ static int __init prom_find_machine_type(void) int x; #endif - /* Look for a PowerMac */ + /* Look for a PowerMac or a Cell */ len = prom_getprop(_prom->root, "compatible", compat, sizeof(compat)-1); if (len > 0) { @@ -1889,7 +1966,11 @@ static int __init prom_find_machine_type(void) } } #ifdef CONFIG_PPC64 - /* If not a mac, try to figure out if it's an IBM pSeries or any other + /* Try to detect OPAL */ + if (PHANDLE_VALID(call_prom("finddevice", 1, 1, ADDR("/ibm,opal")))) + return PLATFORM_OPAL; + + /* Try to figure out if it's an IBM pSeries or any other * PAPR compliant platform. We assume it is if : * - /device_type is "chrp" (please, do NOT use that for future * non-IBM designs ! @@ -2116,7 +2197,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, unsigned long soff; unsigned char *valp; static char pname[MAX_PROPERTY_NAME]; - int l, room; + int l, room, has_phandle = 0; dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); @@ -2200,19 +2281,26 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, valp = make_room(mem_start, mem_end, l, 4); call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); *mem_start = _ALIGN(*mem_start, 4); + + if (!strcmp(RELOC(pname), RELOC("phandle"))) + has_phandle = 1; } - /* Add a "linux,phandle" property. */ - soff = dt_find_string(RELOC("linux,phandle")); - if (soff == 0) - prom_printf("WARNING: Can't find string index for" - " node %s\n", path); - else { - dt_push_token(OF_DT_PROP, mem_start, mem_end); - dt_push_token(4, mem_start, mem_end); - dt_push_token(soff, mem_start, mem_end); - valp = make_room(mem_start, mem_end, 4, 4); - *(u32 *)valp = node; + /* Add a "linux,phandle" property if no "phandle" property already + * existed (can happen with OPAL) + */ + if (!has_phandle) { + soff = dt_find_string(RELOC("linux,phandle")); + if (soff == 0) + prom_printf("WARNING: Can't find string index for" + " node %s\n", path); + else { + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(4, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + valp = make_room(mem_start, mem_end, 4, 4); + *(u32 *)valp = node; + } } /* do all our children */ @@ -2746,6 +2834,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, * between pSeries SMP and pSeries LPAR */ RELOC(of_platform) = prom_find_machine_type(); + prom_printf("Detected machine type: %x\n", RELOC(of_platform)); #ifndef CONFIG_RELOCATABLE /* Bail if this is a kdump kernel. */ @@ -2807,7 +2896,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, * On non-powermacs, try to instantiate RTAS. PowerMacs don't * have a usable RTAS implementation. */ - if (RELOC(of_platform) != PLATFORM_POWERMAC) + if (RELOC(of_platform) != PLATFORM_POWERMAC && + RELOC(of_platform) != PLATFORM_OPAL) prom_instantiate_rtas(); #ifdef CONFIG_PPC_POWERNV @@ -2818,7 +2908,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, prom_opal_hold_cpus(); prom_opal_takeover(); } - } + } else if (RELOC(of_platform) == PLATFORM_OPAL) + prom_instantiate_opal(); #endif /* @@ -2826,7 +2917,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, * * PowerMacs use a different mechanism to spin CPUs */ - if (RELOC(of_platform) != PLATFORM_POWERMAC) + if (RELOC(of_platform) != PLATFORM_POWERMAC && + RELOC(of_platform) != PLATFORM_OPAL) prom_hold_cpus(); /* @@ -2894,7 +2986,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, reloc_got2(-offset); #endif - __start(hdr, kbase, 0); +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL + /* OPAL early debug gets the OPAL base & entry in r8 and r9 */ + __start(hdr, kbase, 0, 0, 0, + RELOC(prom_opal_base), RELOC(prom_opal_entry)); +#else + __start(hdr, kbase, 0, 0, 0, 0, 0); +#endif return 0; } From daea1175a9f0f70eab5b33e2827d57ba8c686816 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:44:59 +0000 Subject: [PATCH 0423/1596] powerpc/powernv: Support for OPAL console This adds a udbg and an hvc console backend for supporting a console using the OPAL console interfaces. On OPAL v1 we have hvc0 mapped to whatever console the system was configured for (network or hvsi serial port) via the service processor. On OPAL v2 we have hvcN mapped to the Nth console provided by OPAL which generally corresponds to: hvc0 : network console (raw protocol) hvc1 : serial port S1 (hvsi) hvc2 : serial port S2 (hvsi) Note: At this point, early debug console only works with OPAL v1 and shouldn't be enabled in a normal kernel. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Kconfig.debug | 31 ++ arch/powerpc/include/asm/opal.h | 5 + arch/powerpc/include/asm/udbg.h | 2 + arch/powerpc/kernel/head_64.S | 14 +- arch/powerpc/kernel/udbg.c | 4 + arch/powerpc/platforms/powernv/opal.c | 31 +- arch/powerpc/platforms/powernv/setup.c | 14 +- drivers/tty/hvc/Kconfig | 9 + drivers/tty/hvc/Makefile | 1 + drivers/tty/hvc/hvc_opal.c | 424 +++++++++++++++++++++++++ drivers/tty/hvc/hvsi_lib.c | 4 +- 11 files changed, 517 insertions(+), 22 deletions(-) create mode 100644 drivers/tty/hvc/hvc_opal.c diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 06eb62b0fd90..1b8a9c905cf7 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -265,8 +265,27 @@ config PPC_EARLY_DEBUG_PS3GELIC Select this to enable early debugging for the PlayStation3 via UDP broadcasts sent out through the Ethernet port. +config PPC_EARLY_DEBUG_OPAL_RAW + bool "OPAL raw console" + depends on HVC_OPAL + help + Select this to enable early debugging for the PowerNV platform + using a "raw" console + +config PPC_EARLY_DEBUG_OPAL_HVSI + bool "OPAL hvsi console" + depends on HVC_OPAL + help + Select this to enable early debugging for the PowerNV platform + using an "hvsi" console + endchoice +config PPC_EARLY_DEBUG_OPAL + def_bool y + depends on PPC_EARLY_DEBUG_OPAL_RAW || PPC_EARLY_DEBUG_OPAL_HVSI + + config PPC_EARLY_DEBUG_HVSI_VTERMNO hex "vterm number to use with early debug HVSI" depends on PPC_EARLY_DEBUG_LPAR_HVSI @@ -275,6 +294,18 @@ config PPC_EARLY_DEBUG_HVSI_VTERMNO You probably want 0x30000000 for your first serial port and 0x30000001 for your second one +config PPC_EARLY_DEBUG_OPAL_VTERMNO + hex "vterm number to use with OPAL early debug" + depends on PPC_EARLY_DEBUG_OPAL + default "0" + help + This correspond to which /dev/hvcN you want to use for early + debug. + + On OPAL v1 (takeover) this should always be 0 + On OPAL v2, this will be 0 for network console and 1 or 2 for + the machine built-in serial ports. + config PPC_EARLY_DEBUG_44x_PHYSLOW hex "Low 32 bits of early debug UART physical address" depends on PPC_EARLY_DEBUG_44x diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index c7a3202d10a0..749de00a02d5 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -425,6 +425,11 @@ extern void hvc_opal_init_early(void); extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data); +extern int opal_get_chars(uint32_t vtermno, char *buf, int count); +extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); + +extern void hvc_opal_init_early(void); + #endif /* __ASSEMBLY__ */ #endif /* __OPAL_H */ diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h index 7cf796fa03f2..6587ec7bc6ec 100644 --- a/arch/powerpc/include/asm/udbg.h +++ b/arch/powerpc/include/asm/udbg.h @@ -55,6 +55,8 @@ extern void __init udbg_init_cpm(void); extern void __init udbg_init_usbgecko(void); extern void __init udbg_init_wsp(void); extern void __init udbg_init_ps3gelic(void); +extern void __init udbg_init_debug_opal_raw(void); +extern void __init udbg_init_debug_opal_hvsi(void); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_UDBG_H */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index dea8191253d2..06c7251c1bf7 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -53,7 +53,8 @@ * 2. The kernel is entered at __start * -or- For OPAL entry: * 1. The MMU is off, processor in HV mode, primary CPU enters at 0 - * with device-tree in gpr3 + * with device-tree in gpr3. We also get OPAL base in r8 and + * entry in r9 for debugging purposes * 2. Secondary processors enter at 0x60 with PIR in gpr3 * * For iSeries: @@ -335,6 +336,11 @@ _GLOBAL(__start_initialization_multiplatform) /* Save parameters */ mr r31,r3 mr r30,r4 +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL + /* Save OPAL entry */ + mr r28,r8 + mr r29,r9 +#endif #ifdef CONFIG_PPC_BOOK3E bl .start_initialization_book3e @@ -711,6 +717,12 @@ _INIT_STATIC(start_here_multiplatform) bdnz 3b 4: +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL + /* Setup OPAL entry */ + std r28,0(r11); + std r29,8(r11); +#endif + #ifndef CONFIG_PPC_BOOK3E mfmsr r6 ori r6,r6,MSR_RI diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 5b3e98e03158..35f948203ec5 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -69,6 +69,10 @@ void __init udbg_early_init(void) udbg_init_wsp(); #elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC) udbg_init_ps3gelic(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_RAW) + udbg_init_debug_opal_raw(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI) + udbg_init_debug_opal_hvsi(); #endif #ifdef CONFIG_PPC_EARLY_DEBUG diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 8d5510784cc2..7887733b9b31 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -67,7 +67,7 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count) u64 evt; if (!opal.entry) - return 0; + return -ENODEV; opal_poll_events(&evt); if ((evt & OPAL_EVENT_CONSOLE_INPUT) == 0) return 0; @@ -81,31 +81,38 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count) int opal_put_chars(uint32_t vtermno, const char *data, int total_len) { int written = 0; - s64 len, rc = OPAL_BUSY; + s64 len, rc; unsigned long flags; u64 evt; if (!opal.entry) - return 0; + return -ENODEV; /* We want put_chars to be atomic to avoid mangling of hvsi * packets. To do that, we first test for room and return - * -EAGAIN if there isn't enough + * -EAGAIN if there isn't enough. + * + * Unfortunately, opal_console_write_buffer_space() doesn't + * appear to work on opal v1, so we just assume there is + * enough room and be done with it */ spin_lock_irqsave(&opal_write_lock, flags); - rc = opal_console_write_buffer_space(vtermno, &len); - if (rc || len < total_len) { - spin_unlock_irqrestore(&opal_write_lock, flags); - /* Closed -> drop characters */ - if (rc) - return total_len; - opal_poll_events(&evt); - return -EAGAIN; + if (firmware_has_feature(FW_FEATURE_OPALv2)) { + rc = opal_console_write_buffer_space(vtermno, &len); + if (rc || len < total_len) { + spin_unlock_irqrestore(&opal_write_lock, flags); + /* Closed -> drop characters */ + if (rc) + return total_len; + opal_poll_events(&evt); + return -EAGAIN; + } } /* We still try to handle partial completions, though they * should no longer happen. */ + rc = OPAL_BUSY; while(total_len > 0 && (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) { len = total_len; diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index b6e5ff85cc6f..07ba1ecd1807 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -29,17 +29,12 @@ #include #include #include +#include #include "powernv.h" static void __init pnv_setup_arch(void) { - /* Force console to hvc for now until we have sorted out the - * real console situation for the platform. This will make - * hvc_udbg work at least. - */ - add_preferred_console("hvc", 0, NULL); - /* Initialize SMP */ pnv_smp_init(); @@ -55,7 +50,12 @@ static void __init pnv_setup_arch(void) static void __init pnv_init_early(void) { - /* XXX IOMMU */ +#ifdef CONFIG_HVC_OPAL + if (firmware_has_feature(FW_FEATURE_OPAL)) + hvc_opal_init_early(); + else +#endif + add_preferred_console("hvc", 0, NULL); } static void __init pnv_init_IRQ(void) diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index e371753ba921..4222035acfb7 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig @@ -34,6 +34,15 @@ config HVC_ISERIES help iSeries machines support a hypervisor virtual console. +config HVC_OPAL + bool "OPAL Console support" + depends on PPC_POWERNV + select HVC_DRIVER + select HVC_IRQ + default y + help + PowerNV machines running under OPAL need that driver to get a console + config HVC_RTAS bool "IBM RTAS Console support" depends on PPC_RTAS diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index e29205316376..89abf40bc73d 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o +obj-$(CONFIG_HVC_OPAL) += hvc_opal.o hvsi_lib.o obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c new file mode 100644 index 000000000000..7b38512d6c41 --- /dev/null +++ b/drivers/tty/hvc/hvc_opal.c @@ -0,0 +1,424 @@ +/* + * opal driver interface to hvc_console.c + * + * Copyright 2011 Benjamin Herrenschmidt , IBM Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "hvc_console.h" + +static const char hvc_opal_name[] = "hvc_opal"; + +static struct of_device_id hvc_opal_match[] __devinitdata = { + { .name = "serial", .compatible = "ibm,opal-console-raw" }, + { .name = "serial", .compatible = "ibm,opal-console-hvsi" }, + { }, +}; + +typedef enum hv_protocol { + HV_PROTOCOL_RAW, + HV_PROTOCOL_HVSI +} hv_protocol_t; + +struct hvc_opal_priv { + hv_protocol_t proto; /* Raw data or HVSI packets */ + struct hvsi_priv hvsi; /* HVSI specific data */ +}; +static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES]; + +/* For early boot console */ +static struct hvc_opal_priv hvc_opal_boot_priv; +static u32 hvc_opal_boot_termno; + +static const struct hv_ops hvc_opal_raw_ops = { + .get_chars = opal_get_chars, + .put_chars = opal_put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, + .notifier_hangup = notifier_hangup_irq, +}; + +static int hvc_opal_hvsi_get_chars(uint32_t vtermno, char *buf, int count) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[vtermno]; + + if (WARN_ON(!pv)) + return -ENODEV; + + return hvsilib_get_chars(&pv->hvsi, buf, count); +} + +static int hvc_opal_hvsi_put_chars(uint32_t vtermno, const char *buf, int count) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[vtermno]; + + if (WARN_ON(!pv)) + return -ENODEV; + + return hvsilib_put_chars(&pv->hvsi, buf, count); +} + +static int hvc_opal_hvsi_open(struct hvc_struct *hp, int data) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + int rc; + + pr_devel("HVSI@%x: do open !\n", hp->vtermno); + + rc = notifier_add_irq(hp, data); + if (rc) + return rc; + + return hvsilib_open(&pv->hvsi, hp); +} + +static void hvc_opal_hvsi_close(struct hvc_struct *hp, int data) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + + pr_devel("HVSI@%x: do close !\n", hp->vtermno); + + hvsilib_close(&pv->hvsi, hp); + + notifier_del_irq(hp, data); +} + +void hvc_opal_hvsi_hangup(struct hvc_struct *hp, int data) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + + pr_devel("HVSI@%x: do hangup !\n", hp->vtermno); + + hvsilib_close(&pv->hvsi, hp); + + notifier_hangup_irq(hp, data); +} + +static int hvc_opal_hvsi_tiocmget(struct hvc_struct *hp) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + + if (!pv) + return -EINVAL; + return pv->hvsi.mctrl; +} + +static int hvc_opal_hvsi_tiocmset(struct hvc_struct *hp, unsigned int set, + unsigned int clear) +{ + struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; + + pr_devel("HVSI@%x: Set modem control, set=%x,clr=%x\n", + hp->vtermno, set, clear); + + if (set & TIOCM_DTR) + hvsilib_write_mctrl(&pv->hvsi, 1); + else if (clear & TIOCM_DTR) + hvsilib_write_mctrl(&pv->hvsi, 0); + + return 0; +} + +static const struct hv_ops hvc_opal_hvsi_ops = { + .get_chars = hvc_opal_hvsi_get_chars, + .put_chars = hvc_opal_hvsi_put_chars, + .notifier_add = hvc_opal_hvsi_open, + .notifier_del = hvc_opal_hvsi_close, + .notifier_hangup = hvc_opal_hvsi_hangup, + .tiocmget = hvc_opal_hvsi_tiocmget, + .tiocmset = hvc_opal_hvsi_tiocmset, +}; + +static int __devinit hvc_opal_probe(struct platform_device *dev) +{ + const struct hv_ops *ops; + struct hvc_struct *hp; + struct hvc_opal_priv *pv; + hv_protocol_t proto; + unsigned int termno, boot = 0; + const __be32 *reg; + + if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) { + proto = HV_PROTOCOL_RAW; + ops = &hvc_opal_raw_ops; + } else if (of_device_is_compatible(dev->dev.of_node, + "ibm,opal-console-hvsi")) { + proto = HV_PROTOCOL_HVSI; + ops = &hvc_opal_hvsi_ops; + } else { + pr_err("hvc_opal: Unkown protocol for %s\n", + dev->dev.of_node->full_name); + return -ENXIO; + } + + reg = of_get_property(dev->dev.of_node, "reg", NULL); + termno = reg ? be32_to_cpup(reg) : 0; + + /* Is it our boot one ? */ + if (hvc_opal_privs[termno] == &hvc_opal_boot_priv) { + pv = hvc_opal_privs[termno]; + boot = 1; + } else if (hvc_opal_privs[termno] == NULL) { + pv = kzalloc(sizeof(struct hvc_opal_priv), GFP_KERNEL); + if (!pv) + return -ENOMEM; + pv->proto = proto; + hvc_opal_privs[termno] = pv; + if (proto == HV_PROTOCOL_HVSI) + hvsilib_init(&pv->hvsi, opal_get_chars, opal_put_chars, + termno, 0); + + /* Instanciate now to establish a mapping index==vtermno */ + hvc_instantiate(termno, termno, ops); + } else { + pr_err("hvc_opal: Device %s has duplicate terminal number #%d\n", + dev->dev.of_node->full_name, termno); + return -ENXIO; + } + + pr_info("hvc%d: %s protocol on %s%s\n", termno, + proto == HV_PROTOCOL_RAW ? "raw" : "hvsi", + dev->dev.of_node->full_name, + boot ? " (boot console)" : ""); + + /* We don't do IRQ yet */ + hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS); + if (IS_ERR(hp)) + return PTR_ERR(hp); + dev_set_drvdata(&dev->dev, hp); + + return 0; +} + +static int __devexit hvc_opal_remove(struct platform_device *dev) +{ + struct hvc_struct *hp = dev_get_drvdata(&dev->dev); + int rc, termno; + + termno = hp->vtermno; + rc = hvc_remove(hp); + if (rc == 0) { + if (hvc_opal_privs[termno] != &hvc_opal_boot_priv) + kfree(hvc_opal_privs[termno]); + hvc_opal_privs[termno] = NULL; + } + return rc; +} + +static struct platform_driver hvc_opal_driver = { + .probe = hvc_opal_probe, + .remove = __devexit_p(hvc_opal_remove), + .driver = { + .name = hvc_opal_name, + .owner = THIS_MODULE, + .of_match_table = hvc_opal_match, + } +}; + +static int __init hvc_opal_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_OPAL)) + return -ENODEV; + + /* Register as a vio device to receive callbacks */ + return platform_driver_register(&hvc_opal_driver); +} +module_init(hvc_opal_init); + +static void __exit hvc_opal_exit(void) +{ + platform_driver_unregister(&hvc_opal_driver); +} +module_exit(hvc_opal_exit); + +static void udbg_opal_putc(char c) +{ + unsigned int termno = hvc_opal_boot_termno; + int count = -1; + + if (c == '\n') + udbg_opal_putc('\r'); + + do { + switch(hvc_opal_boot_priv.proto) { + case HV_PROTOCOL_RAW: + count = opal_put_chars(termno, &c, 1); + break; + case HV_PROTOCOL_HVSI: + count = hvc_opal_hvsi_put_chars(termno, &c, 1); + break; + } + } while(count == 0 || count == -EAGAIN); +} + +static int udbg_opal_getc_poll(void) +{ + unsigned int termno = hvc_opal_boot_termno; + int rc = 0; + char c; + + switch(hvc_opal_boot_priv.proto) { + case HV_PROTOCOL_RAW: + rc = opal_get_chars(termno, &c, 1); + break; + case HV_PROTOCOL_HVSI: + rc = hvc_opal_hvsi_get_chars(termno, &c, 1); + break; + } + if (!rc) + return -1; + return c; +} + +static int udbg_opal_getc(void) +{ + int ch; + for (;;) { + ch = udbg_opal_getc_poll(); + if (ch == -1) { + /* This shouldn't be needed...but... */ + volatile unsigned long delay; + for (delay=0; delay < 2000000; delay++) + ; + } else { + return ch; + } + } +} + +static void udbg_init_opal_common(void) +{ + udbg_putc = udbg_opal_putc; + udbg_getc = udbg_opal_getc; + udbg_getc_poll = udbg_opal_getc_poll; + tb_ticks_per_usec = 0x200; /* Make udelay not suck */ +} + +void __init hvc_opal_init_early(void) +{ + struct device_node *stdout_node = NULL; + const u32 *termno; + const char *name = NULL; + const struct hv_ops *ops; + u32 index; + + /* find the boot console from /chosen/stdout */ + if (of_chosen) + name = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (name) { + stdout_node = of_find_node_by_path(name); + if (!stdout_node) { + pr_err("hvc_opal: Failed to locate default console!\n"); + return; + } + } else { + struct device_node *opal, *np; + + /* Current OPAL takeover doesn't provide the stdout + * path, so we hard wire it + */ + opal = of_find_node_by_path("/ibm,opal/consoles"); + if (opal) + pr_devel("hvc_opal: Found consoles in new location\n"); + if (!opal) { + opal = of_find_node_by_path("/ibm,opal"); + if (opal) + pr_devel("hvc_opal: " + "Found consoles in old location\n"); + } + if (!opal) + return; + for_each_child_of_node(opal, np) { + if (!strcmp(np->name, "serial")) { + stdout_node = np; + break; + } + } + of_node_put(opal); + } + if (!stdout_node) + return; + termno = of_get_property(stdout_node, "reg", NULL); + index = termno ? *termno : 0; + if (index >= MAX_NR_HVC_CONSOLES) + return; + hvc_opal_privs[index] = &hvc_opal_boot_priv; + + /* Check the protocol */ + if (of_device_is_compatible(stdout_node, "ibm,opal-console-raw")) { + hvc_opal_boot_priv.proto = HV_PROTOCOL_RAW; + ops = &hvc_opal_raw_ops; + pr_devel("hvc_opal: Found RAW console\n"); + } + else if (of_device_is_compatible(stdout_node,"ibm,opal-console-hvsi")) { + hvc_opal_boot_priv.proto = HV_PROTOCOL_HVSI; + ops = &hvc_opal_hvsi_ops; + hvsilib_init(&hvc_opal_boot_priv.hvsi, opal_get_chars, + opal_put_chars, index, 1); + /* HVSI, perform the handshake now */ + hvsilib_establish(&hvc_opal_boot_priv.hvsi); + pr_devel("hvc_opal: Found HVSI console\n"); + } else + goto out; + hvc_opal_boot_termno = index; + udbg_init_opal_common(); + add_preferred_console("hvc", index, NULL); + hvc_instantiate(index, index, ops); +out: + of_node_put(stdout_node); +} + +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_RAW +void __init udbg_init_debug_opal(void) +{ + u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO; + hvc_opal_privs[index] = &hvc_opal_boot_priv; + hvc_opal_boot_priv.proto = HV_PROTOCOL_RAW; + hvc_opal_boot_termno = index; + udbg_init_opal_common(); +} +#endif /* CONFIG_PPC_EARLY_DEBUG_OPAL_RAW */ + +#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI +void __init udbg_init_debug_opal_hvsi(void) +{ + u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO; + hvc_opal_privs[index] = &hvc_opal_boot_priv; + hvc_opal_boot_termno = index; + udbg_init_opal_common(); + hvsilib_init(&hvc_opal_boot_priv.hvsi, opal_get_chars, opal_put_chars, + index, 1); + hvsilib_establish(&hvc_opal_boot_priv.hvsi); +} +#endif /* CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI */ diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index bd9b09827b24..6f4dd83d8695 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -183,7 +183,7 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count) unsigned int tries, read = 0; if (WARN_ON(!pv)) - return 0; + return -ENXIO; /* If we aren't open, don't do anything in order to avoid races * with connection establishment. The hvc core will call this @@ -234,7 +234,7 @@ int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count) int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA); if (WARN_ON(!pv)) - return 0; + return -ENODEV; dp.hdr.type = VS_DATA_PACKET_HEADER; dp.hdr.len = adjcount + sizeof(struct hvsi_header); From ec27329ffb3b4f619be9f0065c473fcb36ea52ce Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 18:28:03 +0000 Subject: [PATCH 0424/1596] powerpc/powernv: Hookup reboot and poweroff functions This calls the respective HAL functions, and spin on hal_poll_event() to ensure the HAL has a chance to communicate with the FSP to trigger the reboot or shutdown operation Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/setup.c | 32 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 07ba1ecd1807..0fac0a6c951e 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -83,19 +83,39 @@ static void pnv_show_cpuinfo(struct seq_file *m) of_node_put(root); } -static void pnv_restart(char *cmd) +static void __noreturn pnv_restart(char *cmd) { - for (;;); + long rc = OPAL_BUSY; + + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_cec_reboot(); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + mdelay(10); + } + for (;;) + opal_poll_events(NULL); } -static void pnv_power_off(void) +static void __noreturn pnv_power_off(void) { - for (;;); + long rc = OPAL_BUSY; + + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_cec_power_down(0); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + mdelay(10); + } + for (;;) + opal_poll_events(NULL); } -static void pnv_halt(void) +static void __noreturn pnv_halt(void) { - for (;;); + pnv_power_off(); } static unsigned long __init pnv_get_boot_time(void) From 628daa8d5abfd904a7329a660c5c374212230123 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:45:01 +0000 Subject: [PATCH 0425/1596] powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks Implements OPAL RTC and NVRAM support and wire all that up to the powernv platform. We use RTAS for RTC as a fallback if available. Using RTAS for nvram is not supported yet, pending some rework/cleanup and generalization of the pSeries & CHRP code. We also use RTAS fallbacks for power off and reboot Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/opal.h | 6 ++ arch/powerpc/platforms/powernv/Makefile | 2 + arch/powerpc/platforms/powernv/opal-nvram.c | 88 +++++++++++++++++++ arch/powerpc/platforms/powernv/opal-rtc.c | 97 +++++++++++++++++++++ arch/powerpc/platforms/powernv/setup.c | 57 +++++++----- 5 files changed, 229 insertions(+), 21 deletions(-) create mode 100644 arch/powerpc/platforms/powernv/opal-nvram.c create mode 100644 arch/powerpc/platforms/powernv/opal-rtc.c diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 749de00a02d5..77ebe50020a2 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -430,6 +430,12 @@ extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); extern void hvc_opal_init_early(void); +struct rtc_time; +extern int opal_set_rtc_time(struct rtc_time *tm); +extern void opal_get_rtc_time(struct rtc_time *tm); +extern unsigned long opal_get_boot_time(void); +extern void opal_nvram_init(void); + #endif /* __ASSEMBLY__ */ #endif /* __OPAL_H */ diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 8f69c0db612c..618ad836f28b 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -1,2 +1,4 @@ obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o +obj-y += opal-rtc.o opal-nvram.o + obj-$(CONFIG_SMP) += smp.o diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c new file mode 100644 index 000000000000..3f83e1ae26ac --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-nvram.c @@ -0,0 +1,88 @@ +/* + * PowerNV nvram code. + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#define DEBUG + +#include +#include +#include + +#include +#include + +static unsigned int nvram_size; + +static ssize_t opal_nvram_size(void) +{ + return nvram_size; +} + +static ssize_t opal_nvram_read(char *buf, size_t count, loff_t *index) +{ + s64 rc; + int off; + + if (*index >= nvram_size) + return 0; + off = *index; + if ((off + count) > nvram_size) + count = nvram_size - off; + rc = opal_read_nvram(__pa(buf), count, off); + if (rc != OPAL_SUCCESS) + return -EIO; + *index += count; + return count; +} + +static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) +{ + s64 rc = OPAL_BUSY; + int off; + + if (*index >= nvram_size) + return 0; + off = *index; + if ((off + count) > nvram_size) + count = nvram_size - off; + + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_write_nvram(__pa(buf), count, off); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + } + *index += count; + return count; +} + +void __init opal_nvram_init(void) +{ + struct device_node *np; + const u32 *nbytes_p; + + np = of_find_compatible_node(NULL, NULL, "ibm,opal-nvram"); + if (np == NULL) + return; + + nbytes_p = of_get_property(np, "#bytes", NULL); + if (!nbytes_p) { + of_node_put(np); + return; + } + nvram_size = *nbytes_p; + + printk(KERN_INFO "OPAL nvram setup, %u bytes\n", nvram_size); + of_node_put(np); + + ppc_md.nvram_read = opal_nvram_read; + ppc_md.nvram_write = opal_nvram_write; + ppc_md.nvram_size = opal_nvram_size; +} + diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c new file mode 100644 index 000000000000..2aa7641aac9b --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-rtc.c @@ -0,0 +1,97 @@ +/* + * PowerNV Real Time Clock. + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + +#include +#include +#include +#include +#include + +#include +#include + +static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm) +{ + tm->tm_year = ((bcd2bin(y_m_d >> 24) * 100) + + bcd2bin((y_m_d >> 16) & 0xff)) - 1900; + tm->tm_mon = bcd2bin((y_m_d >> 8) & 0xff) - 1; + tm->tm_mday = bcd2bin(y_m_d & 0xff); + tm->tm_hour = bcd2bin((h_m_s_ms >> 56) & 0xff); + tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff); + tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff); + + GregorianDay(tm); +} + +unsigned long __init opal_get_boot_time(void) +{ + struct rtc_time tm; + u32 y_m_d; + u64 h_m_s_ms; + long rc = OPAL_BUSY; + + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_rtc_read(&y_m_d, &h_m_s_ms); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + mdelay(10); + } + if (rc != OPAL_SUCCESS) + return 0; + opal_to_tm(y_m_d, h_m_s_ms, &tm); + return mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +} + +void opal_get_rtc_time(struct rtc_time *tm) +{ + long rc = OPAL_BUSY; + u32 y_m_d; + u64 h_m_s_ms; + + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_rtc_read(&y_m_d, &h_m_s_ms); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + mdelay(10); + } + if (rc != OPAL_SUCCESS) + return; + opal_to_tm(y_m_d, h_m_s_ms, tm); +} + +int opal_set_rtc_time(struct rtc_time *tm) +{ + long rc = OPAL_BUSY; + u32 y_m_d = 0; + u64 h_m_s_ms = 0; + + y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) / 100)) << 24; + y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) % 100)) << 16; + y_m_d |= ((u32)bin2bcd((tm->tm_mon + 1))) << 8; + y_m_d |= ((u32)bin2bcd(tm->tm_mday)); + + h_m_s_ms |= ((u64)bin2bcd(tm->tm_hour)) << 56; + h_m_s_ms |= ((u64)bin2bcd(tm->tm_min)) << 48; + h_m_s_ms |= ((u64)bin2bcd(tm->tm_sec)) << 40; + + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_rtc_write(y_m_d, h_m_s_ms); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + mdelay(10); + } + return rc == OPAL_SUCCESS ? 0 : -EIO; +} diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 0fac0a6c951e..4a2b2e279593 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include #include "powernv.h" @@ -40,7 +42,9 @@ static void __init pnv_setup_arch(void) /* XXX PCI */ - /* XXX NVRAM */ + /* Setup RTC and NVRAM callbacks */ + if (firmware_has_feature(FW_FEATURE_OPAL)) + opal_nvram_init(); /* Enable NAP mode */ powersave_nap = 1; @@ -118,30 +122,40 @@ static void __noreturn pnv_halt(void) pnv_power_off(); } -static unsigned long __init pnv_get_boot_time(void) -{ - return 0; -} - -static void pnv_get_rtc_time(struct rtc_time *rtc_tm) +static void pnv_progress(char *s, unsigned short hex) { } -static int pnv_set_rtc_time(struct rtc_time *tm) +#ifdef CONFIG_KEXEC +static void pnv_kexec_cpu_down(int crash_shutdown, int secondary) { - return 0; + xics_kexec_teardown_cpu(secondary); } +#endif /* CONFIG_KEXEC */ -static void pnv_progress(char *s, unsigned short hex) +static void __init pnv_setup_machdep_opal(void) { + ppc_md.get_boot_time = opal_get_boot_time; + ppc_md.get_rtc_time = opal_get_rtc_time; + ppc_md.set_rtc_time = opal_set_rtc_time; + ppc_md.restart = pnv_restart; + ppc_md.power_off = pnv_power_off; + ppc_md.halt = pnv_halt; } -#ifdef CONFIG_KEXEC -static void pnv_kexec_cpu_down(int crash_shutdown, int secondary) +#ifdef CONFIG_PPC_POWERNV_RTAS +static void __init pnv_setup_machdep_rtas(void) { - xics_kexec_teardown_cpu(secondary); + if (rtas_token("get-time-of-day") != RTAS_UNKNOWN_SERVICE) { + ppc_md.get_boot_time = rtas_get_boot_time; + ppc_md.get_rtc_time = rtas_get_rtc_time; + ppc_md.set_rtc_time = rtas_set_rtc_time; + } + ppc_md.restart = rtas_restart; + ppc_md.power_off = rtas_power_off; + ppc_md.halt = rtas_halt; } -#endif /* CONFIG_KEXEC */ +#endif /* CONFIG_PPC_POWERNV_RTAS */ static int __init pnv_probe(void) { @@ -152,6 +166,13 @@ static int __init pnv_probe(void) hpte_init_native(); + if (firmware_has_feature(FW_FEATURE_OPAL)) + pnv_setup_machdep_opal(); +#ifdef CONFIG_PPC_POWERNV_RTAS + else if (rtas.base) + pnv_setup_machdep_rtas(); +#endif /* CONFIG_PPC_POWERNV_RTAS */ + pr_debug("PowerNV detected !\n"); return 1; @@ -160,16 +181,10 @@ static int __init pnv_probe(void) define_machine(powernv) { .name = "PowerNV", .probe = pnv_probe, - .setup_arch = pnv_setup_arch, .init_early = pnv_init_early, + .setup_arch = pnv_setup_arch, .init_IRQ = pnv_init_IRQ, .show_cpuinfo = pnv_show_cpuinfo, - .restart = pnv_restart, - .power_off = pnv_power_off, - .halt = pnv_halt, - .get_boot_time = pnv_get_boot_time, - .get_rtc_time = pnv_get_rtc_time, - .set_rtc_time = pnv_set_rtc_time, .progress = pnv_progress, .power_save = power7_idle, .calibrate_decr = generic_calibrate_decr, From 5c7c1e9444d8bfb721a27a35bba3eeb5236c75d8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:45:02 +0000 Subject: [PATCH 0426/1596] powerpc/powernv: Add OPAL ICS backend OPAL handles HW access to the various ICS or equivalent chips for us (with the exception of p5ioc2 based HEA which uses a different backend) similarily to what RTAS does on pSeries. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/xics.h | 19 ++ arch/powerpc/sysdev/xics/Makefile | 1 + arch/powerpc/sysdev/xics/ics-opal.c | 244 +++++++++++++++++++++++++ arch/powerpc/sysdev/xics/xics-common.c | 8 +- 4 files changed, 266 insertions(+), 6 deletions(-) create mode 100644 arch/powerpc/sysdev/xics/ics-opal.c diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index b183a4062011..bd6c401c0ee5 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -27,10 +27,18 @@ #define MAX_NUM_PRIORITIES 3 /* Native ICP */ +#ifdef CONFIG_PPC_ICP_NATIVE extern int icp_native_init(void); +#else +static inline int icp_native_init(void) { return -ENODEV; } +#endif /* PAPR ICP */ +#ifdef CONFIG_PPC_ICP_HV extern int icp_hv_init(void); +#else +static inline int icp_hv_init(void) { return -ENODEV; } +#endif /* ICP ops */ struct icp_ops { @@ -51,7 +59,18 @@ extern const struct icp_ops *icp_ops; extern int ics_native_init(void); /* RTAS ICS */ +#ifdef CONFIG_PPC_ICS_RTAS extern int ics_rtas_init(void); +#else +static inline int ics_rtas_init(void) { return -ENODEV; } +#endif + +/* HAL ICS */ +#ifdef CONFIG_PPC_POWERNV +extern int ics_opal_init(void); +#else +static inline int ics_opal_init(void) { return -ENODEV; } +#endif /* ICS instance, hooked up to chip_data of an irq */ struct ics { diff --git a/arch/powerpc/sysdev/xics/Makefile b/arch/powerpc/sysdev/xics/Makefile index b75a6059337f..c606aa8ba60a 100644 --- a/arch/powerpc/sysdev/xics/Makefile +++ b/arch/powerpc/sysdev/xics/Makefile @@ -4,3 +4,4 @@ obj-y += xics-common.o obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o obj-$(CONFIG_PPC_ICP_HV) += icp-hv.o obj-$(CONFIG_PPC_ICS_RTAS) += ics-rtas.o +obj-$(CONFIG_PPC_POWERNV) += ics-opal.o diff --git a/arch/powerpc/sysdev/xics/ics-opal.c b/arch/powerpc/sysdev/xics/ics-opal.c new file mode 100644 index 000000000000..f7e8609df0d5 --- /dev/null +++ b/arch/powerpc/sysdev/xics/ics-opal.c @@ -0,0 +1,244 @@ +/* + * ICS backend for OPAL managed interrupts. + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static int ics_opal_mangle_server(int server) +{ + /* No link for now */ + return server << 2; +} + +static int ics_opal_unmangle_server(int server) +{ + /* No link for now */ + return server >> 2; +} + +static void ics_opal_unmask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + int64_t rc; + int server; + + pr_devel("ics-hal: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq); + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + + server = xics_get_irq_server(d->irq, d->affinity, 0); + server = ics_opal_mangle_server(server); + + rc = opal_set_xive(hw_irq, server, DEFAULT_PRIORITY); + if (rc != OPAL_SUCCESS) + pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)" + " error %lld\n", + __func__, d->irq, hw_irq, server, rc); +} + +static unsigned int ics_opal_startup(struct irq_data *d) +{ +#ifdef CONFIG_PCI_MSI + /* + * The generic MSI code returns with the interrupt disabled on the + * card, using the MSI mask bits. Firmware doesn't appear to unmask + * at that level, so we do it here by hand. + */ + if (d->msi_desc) + unmask_msi_irq(d); +#endif + + /* unmask it */ + ics_opal_unmask_irq(d); + return 0; +} + +static void ics_opal_mask_real_irq(unsigned int hw_irq) +{ + int server = ics_opal_mangle_server(xics_default_server); + int64_t rc; + + if (hw_irq == XICS_IPI) + return; + + /* Have to set XIVE to 0xff to be able to remove a slot */ + rc = opal_set_xive(hw_irq, server, 0xff); + if (rc != OPAL_SUCCESS) + pr_err("%s: opal_set_xive(0xff) irq=%u returned %lld\n", + __func__, hw_irq, rc); +} + +static void ics_opal_mask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + + pr_devel("ics-hal: mask virq %d [hw 0x%x]\n", d->irq, hw_irq); + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + ics_opal_mask_real_irq(hw_irq); +} + +static int ics_opal_set_affinity(struct irq_data *d, + const struct cpumask *cpumask, + bool force) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + int16_t server; + int8_t priority; + int64_t rc; + int wanted_server; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return -1; + + rc = opal_get_xive(hw_irq, &server, &priority); + if (rc != OPAL_SUCCESS) { + pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)" + " error %lld\n", + __func__, d->irq, hw_irq, server, rc); + return -1; + } + + wanted_server = xics_get_irq_server(d->irq, cpumask, 1); + if (wanted_server < 0) { + char cpulist[128]; + cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); + pr_warning("%s: No online cpus in the mask %s for irq %d\n", + __func__, cpulist, d->irq); + return -1; + } + server = ics_opal_mangle_server(wanted_server); + + pr_devel("ics-hal: set-affinity irq %d [hw 0x%x] server: 0x%x/0x%x\n", + d->irq, hw_irq, wanted_server, server); + + rc = opal_set_xive(hw_irq, server, priority); + if (rc != OPAL_SUCCESS) { + pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)" + " error %lld\n", + __func__, d->irq, hw_irq, server, rc); + return -1; + } + return 0; +} + +static struct irq_chip ics_opal_irq_chip = { + .name = "OPAL ICS", + .irq_startup = ics_opal_startup, + .irq_mask = ics_opal_mask_irq, + .irq_unmask = ics_opal_unmask_irq, + .irq_eoi = NULL, /* Patched at init time */ + .irq_set_affinity = ics_opal_set_affinity +}; + +static int ics_opal_map(struct ics *ics, unsigned int virq); +static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec); +static long ics_opal_get_server(struct ics *ics, unsigned long vec); + +static int ics_opal_host_match(struct ics *ics, struct device_node *node) +{ + return 1; +} + +/* Only one global & state struct ics */ +static struct ics ics_hal = { + .map = ics_opal_map, + .mask_unknown = ics_opal_mask_unknown, + .get_server = ics_opal_get_server, + .host_match = ics_opal_host_match, +}; + +static int ics_opal_map(struct ics *ics, unsigned int virq) +{ + unsigned int hw_irq = (unsigned int)virq_to_hw(virq); + int64_t rc; + int16_t server; + int8_t priority; + + if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)) + return -EINVAL; + + /* Check if HAL knows about this interrupt */ + rc = opal_get_xive(hw_irq, &server, &priority); + if (rc != OPAL_SUCCESS) + return -ENXIO; + + irq_set_chip_and_handler(virq, &ics_opal_irq_chip, handle_fasteoi_irq); + irq_set_chip_data(virq, &ics_hal); + + return 0; +} + +static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec) +{ + int64_t rc; + int16_t server; + int8_t priority; + + /* Check if HAL knows about this interrupt */ + rc = opal_get_xive(vec, &server, &priority); + if (rc != OPAL_SUCCESS) + return; + + ics_opal_mask_real_irq(vec); +} + +static long ics_opal_get_server(struct ics *ics, unsigned long vec) +{ + int64_t rc; + int16_t server; + int8_t priority; + + /* Check if HAL knows about this interrupt */ + rc = opal_get_xive(vec, &server, &priority); + if (rc != OPAL_SUCCESS) + return -1; + return ics_opal_unmangle_server(server); +} + +int __init ics_opal_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_OPAL)) + return -ENODEV; + + /* We need to patch our irq chip's EOI to point to the + * right ICP + */ + ics_opal_irq_chip.irq_eoi = icp_ops->eoi; + + /* Register ourselves */ + xics_register_ics(&ics_hal); + + pr_info("ICS OPAL backend registered\n"); + + return 0; +} diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index 445c5a01b766..3d93a8ded0f8 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -409,14 +409,10 @@ void __init xics_init(void) int rc = -1; /* Fist locate ICP */ -#ifdef CONFIG_PPC_ICP_HV if (firmware_has_feature(FW_FEATURE_LPAR)) rc = icp_hv_init(); -#endif -#ifdef CONFIG_PPC_ICP_NATIVE if (rc < 0) rc = icp_native_init(); -#endif if (rc < 0) { pr_warning("XICS: Cannot find a Presentation Controller !\n"); return; @@ -429,9 +425,9 @@ void __init xics_init(void) xics_ipi_chip.irq_eoi = icp_ops->eoi; /* Now locate ICS */ -#ifdef CONFIG_PPC_ICS_RTAS rc = ics_rtas_init(); -#endif + if (rc < 0) + rc = ics_opal_init(); if (rc < 0) pr_warning("XICS: Cannot find a Source Controller !\n"); From a125e0928c736bc50cdd9a13151d4f4ee7821266 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:45:03 +0000 Subject: [PATCH 0427/1596] powerpc/powernv: Register and handle OPAL interrupts We do the minimum which is to "pass" interrupts to HAL, which makes the console smoother and will allow us to implement interrupt based completion and console. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/opal.c | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 7887733b9b31..5a598caefcba 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -135,9 +136,22 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) return written; } +static irqreturn_t opal_interrupt(int irq, void *data) +{ + uint64_t events; + + opal_handle_interrupt(virq_to_hw(irq), &events); + + /* XXX TODO: Do something with the events */ + + return IRQ_HANDLED; +} + static int __init opal_init(void) { struct device_node *np, *consoles; + const u32 *irqs; + int rc, i, irqlen; opal_node = of_find_node_by_path("/ibm,opal"); if (!opal_node) { @@ -156,6 +170,23 @@ static int __init opal_init(void) of_platform_device_create(np, NULL, NULL); } of_node_put(consoles); + + /* Find all OPAL interrupts and request them */ + irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); + pr_debug("opal: Found %d interrupts reserved for OPAL\n", + irqs ? (irqlen / 4) : 0); + for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) { + unsigned int hwirq = be32_to_cpup(irqs); + unsigned int irq = irq_create_mapping(NULL, hwirq); + if (irq == NO_IRQ) { + pr_warning("opal: Failed to map irq 0x%x\n", hwirq); + continue; + } + rc = request_irq(irq, opal_interrupt, 0, "opal", NULL); + if (rc) + pr_warning("opal: Error %d requesting irq %d" + " (0x%x)\n", rc, irq, hwirq); + } return 0; } subsys_initcall(opal_init); From ed79ba9e15f84cef05aba5cbfe6e93f9b43c31f4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:45:04 +0000 Subject: [PATCH 0428/1596] powerpc/powernv: Machine check and other system interrupts OPAL can handle various interrupt for us such as Machine Checks (it performs all sorts of recovery tasks and passes back control to us with informations about the error), Hardware Management Interrupts and Softpatch interrupts. This wires up the mechanisms and prints out specific informations returned by HAL when a machine check occurs. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/opal.h | 2 + arch/powerpc/include/asm/paca.h | 8 ++ arch/powerpc/kernel/asm-offsets.c | 10 ++ arch/powerpc/kernel/exceptions-64s.S | 27 ++++- arch/powerpc/platforms/powernv/opal.c | 130 +++++++++++++++++++++++++ arch/powerpc/platforms/powernv/setup.c | 1 + 6 files changed, 174 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 77ebe50020a2..2893e8f5406d 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -436,6 +436,8 @@ extern void opal_get_rtc_time(struct rtc_time *tm); extern unsigned long opal_get_boot_time(void); extern void opal_nvram_init(void); +extern int opal_machine_check(struct pt_regs *regs); + #endif /* __ASSEMBLY__ */ #endif /* __OPAL_H */ diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 516bfb3f47d9..17722c73ba2e 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -43,6 +43,7 @@ extern unsigned int debug_smp_processor_id(void); /* from linux/smp.h */ #define get_slb_shadow() (get_paca()->slb_shadow_ptr) struct task_struct; +struct opal_machine_check_event; /* * Defines the layout of the paca. @@ -135,6 +136,13 @@ struct paca_struct { u8 io_sync; /* writel() needs spin_unlock sync */ u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ +#ifdef CONFIG_PPC_POWERNV + /* Pointer to OPAL machine check event structure set by the + * early exception handler for use by high level C handler + */ + struct opal_machine_check_event *opal_mc_evt; +#endif + /* Stuff for accurate time accounting */ u64 user_time; /* accumulated usermode TB ticks */ u64 system_time; /* accumulated system TB ticks */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 5f078bc2063e..536ffa897c6c 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -48,6 +48,9 @@ #ifdef CONFIG_PPC_ISERIES #include #endif +#ifdef CONFIG_PPC_POWERNV +#include +#endif #if defined(CONFIG_KVM) || defined(CONFIG_KVM_GUEST) #include #endif @@ -609,5 +612,12 @@ int main(void) arch.timing_last_enter.tv32.tbl)); #endif +#ifdef CONFIG_PPC_POWERNV + DEFINE(OPAL_MC_GPR3, offsetof(struct opal_machine_check_event, gpr3)); + DEFINE(OPAL_MC_SRR0, offsetof(struct opal_machine_check_event, srr0)); + DEFINE(OPAL_MC_SRR1, offsetof(struct opal_machine_check_event, srr1)); + DEFINE(PACA_OPAL_MC_EVT, offsetof(struct paca_struct, opal_mc_evt)); +#endif + return 0; } diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 41b02c792aa3..d51458fa8dee 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1143,7 +1143,7 @@ _GLOBAL(do_stab_bolted) rfid b . /* prevent speculative execution */ -#ifdef CONFIG_PPC_PSERIES +#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) /* * Data area reserved for FWNMI option. * This address (0x7000) is fixed by the RPA. @@ -1151,7 +1151,7 @@ _GLOBAL(do_stab_bolted) .= 0x7000 .globl fwnmi_data_area fwnmi_data_area: -#endif /* CONFIG_PPC_PSERIES */ +#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ /* iSeries does not use the FWNMI stuff, so it is safe to put * this here, even if we later allow kernels that will boot on @@ -1176,9 +1176,12 @@ xLparMap: #endif /* CONFIG_PPC_ISERIES */ -#ifdef CONFIG_PPC_PSERIES +#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) + /* pseries and powernv need to keep the whole page from + * 0x7000 to 0x8000 free for use by the firmware + */ . = 0x8000 -#endif /* CONFIG_PPC_PSERIES */ +#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ /* * Space for CPU0's segment table. @@ -1193,3 +1196,19 @@ xLparMap: .globl initial_stab initial_stab: .space 4096 +#ifdef CONFIG_PPC_POWERNV +_GLOBAL(opal_mc_secondary_handler) + HMT_MEDIUM + SET_SCRATCH0(r13) + GET_PACA(r13) + clrldi r3,r3,2 + tovirt(r3,r3) + std r3,PACA_OPAL_MC_EVT(r13) + ld r13,OPAL_MC_SRR0(r3) + mtspr SPRN_SRR0,r13 + ld r13,OPAL_MC_SRR1(r3) + mtspr SPRN_SRR1,r13 + ld r3,OPAL_MC_GPR3(r3) + GET_SCRATCH0(r13) + b machine_check_pSeries +#endif /* CONFIG_PPC_POWERNV */ diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 5a598caefcba..aaa0dba49471 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -27,12 +27,14 @@ struct opal { static struct device_node *opal_node; static DEFINE_SPINLOCK(opal_write_lock); +extern u64 opal_mc_secondary_handler[]; int __init early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data) { const void *basep, *entryp; unsigned long basesz, entrysz; + u64 glue; if (depth != 1 || strcmp(uname, "ibm,opal") != 0) return 0; @@ -59,6 +61,19 @@ int __init early_init_dt_scan_opal(unsigned long node, printk("OPAL V1 detected !\n"); } + /* Hookup some exception handlers. We use the fwnmi area at 0x7000 + * to provide the glue space to OPAL + */ + glue = 0x7000; + opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER, + __pa(opal_mc_secondary_handler[0]), + glue); + glue += 128; + opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER, + 0, glue); + glue += 128; + opal_register_exception_handler(OPAL_SOFTPATCH_HANDLER, 0, glue); + return 1; } @@ -136,6 +151,121 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) return written; } +int opal_machine_check(struct pt_regs *regs) +{ + struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt; + struct opal_machine_check_event evt; + const char *level, *sevstr, *subtype; + static const char *opal_mc_ue_types[] = { + "Indeterminate", + "Instruction fetch", + "Page table walk ifetch", + "Load/Store", + "Page table walk Load/Store", + }; + static const char *opal_mc_slb_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + static const char *opal_mc_erat_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + static const char *opal_mc_tlb_types[] = { + "Indeterminate", + "Parity", + "Multihit", + }; + + /* Copy the event structure and release the original */ + evt = *opal_evt; + opal_evt->in_use = 0; + + /* Print things out */ + if (evt.version != OpalMCE_V1) { + pr_err("Machine Check Exception, Unknown event version %d !\n", + evt.version); + return 0; + } + switch(evt.severity) { + case OpalMCE_SEV_NO_ERROR: + level = KERN_INFO; + sevstr = "Harmless"; + break; + case OpalMCE_SEV_WARNING: + level = KERN_WARNING; + sevstr = ""; + break; + case OpalMCE_SEV_ERROR_SYNC: + level = KERN_ERR; + sevstr = "Severe"; + break; + case OpalMCE_SEV_FATAL: + default: + level = KERN_ERR; + sevstr = "Fatal"; + break; + } + + printk("%s%s Machine check interrupt [%s]\n", level, sevstr, + evt.disposition == OpalMCE_DISPOSITION_RECOVERED ? + "Recovered" : "[Not recovered"); + printk("%s Initiator: %s\n", level, + evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown"); + switch(evt.error_type) { + case OpalMCE_ERROR_TYPE_UE: + subtype = evt.u.ue_error.ue_error_type < + ARRAY_SIZE(opal_mc_ue_types) ? + opal_mc_ue_types[evt.u.ue_error.ue_error_type] + : "Unknown"; + printk("%s Error type: UE [%s]\n", level, subtype); + if (evt.u.ue_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt.u.ue_error.effective_address); + if (evt.u.ue_error.physical_address_provided) + printk("%s Physial address: %016llx\n", + level, evt.u.ue_error.physical_address); + break; + case OpalMCE_ERROR_TYPE_SLB: + subtype = evt.u.slb_error.slb_error_type < + ARRAY_SIZE(opal_mc_slb_types) ? + opal_mc_slb_types[evt.u.slb_error.slb_error_type] + : "Unknown"; + printk("%s Error type: SLB [%s]\n", level, subtype); + if (evt.u.slb_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt.u.slb_error.effective_address); + break; + case OpalMCE_ERROR_TYPE_ERAT: + subtype = evt.u.erat_error.erat_error_type < + ARRAY_SIZE(opal_mc_erat_types) ? + opal_mc_erat_types[evt.u.erat_error.erat_error_type] + : "Unknown"; + printk("%s Error type: ERAT [%s]\n", level, subtype); + if (evt.u.erat_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt.u.erat_error.effective_address); + break; + case OpalMCE_ERROR_TYPE_TLB: + subtype = evt.u.tlb_error.tlb_error_type < + ARRAY_SIZE(opal_mc_tlb_types) ? + opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type] + : "Unknown"; + printk("%s Error type: TLB [%s]\n", level, subtype); + if (evt.u.tlb_error.effective_address_provided) + printk("%s Effective address: %016llx\n", + level, evt.u.tlb_error.effective_address); + break; + default: + case OpalMCE_ERROR_TYPE_UNKNOWN: + printk("%s Error type: Unknown\n", level); + break; + } + return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1; +} + static irqreturn_t opal_interrupt(int irq, void *data) { uint64_t events; diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 4a2b2e279593..f0242f3fd3e6 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -141,6 +141,7 @@ static void __init pnv_setup_machdep_opal(void) ppc_md.restart = pnv_restart; ppc_md.power_off = pnv_power_off; ppc_md.halt = pnv_halt; + ppc_md.machine_check_exception = opal_machine_check; } #ifdef CONFIG_PPC_POWERNV_RTAS From 61305a96fad622ae0f0e78cb06f67ad721d378f9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:45:05 +0000 Subject: [PATCH 0429/1596] powerpc/powernv: Add support for p5ioc2 PCI-X and PCIe This adds support for PCI-X and PCIe on the p5ioc2 IO hub using OPAL. This includes allocating & setting up TCE tables and config space access routines. This also supports fallbacks via RTAS when OPAL is absent, using legacy TCE format pre-allocated via the device-tree (BML style) Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/Makefile | 1 + arch/powerpc/platforms/powernv/pci-p5ioc2.c | 185 +++++++++++++ arch/powerpc/platforms/powernv/pci.c | 286 ++++++++++++++++++++ arch/powerpc/platforms/powernv/pci.h | 38 +++ arch/powerpc/platforms/powernv/powernv.h | 6 + arch/powerpc/platforms/powernv/setup.c | 3 +- 6 files changed, 518 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/powernv/pci-p5ioc2.c create mode 100644 arch/powerpc/platforms/powernv/pci.c create mode 100644 arch/powerpc/platforms/powernv/pci.h diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 618ad836f28b..31853008b418 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -2,3 +2,4 @@ obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o obj-y += opal-rtc.o opal-nvram.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c new file mode 100644 index 000000000000..afabc2bcae45 --- /dev/null +++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c @@ -0,0 +1,185 @@ +/* + * Support PCI/PCIe on PowerNV platforms + * + * Currently supports only P5IOC2 + * + * Copyright 2011 Benjamin Herrenschmidt, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "powernv.h" +#include "pci.h" + +/* For now, use a fixed amount of TCE memory for each p5ioc2 + * hub, 16M will do + */ +#define P5IOC2_TCE_MEMORY 0x01000000 + +static void __devinit pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb, + struct pci_dev *pdev) +{ + if (phb->p5ioc2.iommu_table.it_map == NULL) + iommu_init_table(&phb->p5ioc2.iommu_table, phb->hose->node); + + set_iommu_table_base(&pdev->dev, &phb->p5ioc2.iommu_table); +} + +static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, + void *tce_mem, u64 tce_size) +{ + struct pnv_phb *phb; + const u64 *prop64; + u64 phb_id; + int64_t rc; + static int primary = 1; + + pr_info(" Initializing p5ioc2 PHB %s\n", np->full_name); + + prop64 = of_get_property(np, "ibm,opal-phbid", NULL); + if (!prop64) { + pr_err(" Missing \"ibm,opal-phbid\" property !\n"); + return; + } + phb_id = be64_to_cpup(prop64); + pr_devel(" PHB-ID : 0x%016llx\n", phb_id); + pr_devel(" TCE AT : 0x%016lx\n", __pa(tce_mem)); + pr_devel(" TCE SZ : 0x%016llx\n", tce_size); + + rc = opal_pci_set_phb_tce_memory(phb_id, __pa(tce_mem), tce_size); + if (rc != OPAL_SUCCESS) { + pr_err(" Failed to set TCE memory, OPAL error %lld\n", rc); + return; + } + + phb = alloc_bootmem(sizeof(struct pnv_phb)); + if (phb) { + memset(phb, 0, sizeof(struct pnv_phb)); + phb->hose = pcibios_alloc_controller(np); + } + if (!phb || !phb->hose) { + pr_err(" Failed to allocate PCI controller\n"); + return; + } + + spin_lock_init(&phb->lock); + phb->hose->first_busno = 0; + phb->hose->last_busno = 0xff; + phb->hose->private_data = phb; + phb->opal_id = phb_id; + phb->type = PNV_PHB_P5IOC2; + + phb->regs = of_iomap(np, 0); + + if (phb->regs == NULL) + pr_err(" Failed to map registers !\n"); + else { + pr_devel(" P_BUID = 0x%08x\n", in_be32(phb->regs + 0x100)); + pr_devel(" P_IOSZ = 0x%08x\n", in_be32(phb->regs + 0x1b0)); + pr_devel(" P_IO_ST = 0x%08x\n", in_be32(phb->regs + 0x1e0)); + pr_devel(" P_MEM1_H = 0x%08x\n", in_be32(phb->regs + 0x1a0)); + pr_devel(" P_MEM1_L = 0x%08x\n", in_be32(phb->regs + 0x190)); + pr_devel(" P_MSZ1_L = 0x%08x\n", in_be32(phb->regs + 0x1c0)); + pr_devel(" P_MEM_ST = 0x%08x\n", in_be32(phb->regs + 0x1d0)); + pr_devel(" P_MEM2_H = 0x%08x\n", in_be32(phb->regs + 0x2c0)); + pr_devel(" P_MEM2_L = 0x%08x\n", in_be32(phb->regs + 0x2b0)); + pr_devel(" P_MSZ2_H = 0x%08x\n", in_be32(phb->regs + 0x2d0)); + pr_devel(" P_MSZ2_L = 0x%08x\n", in_be32(phb->regs + 0x2e0)); + } + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pci_process_bridge_OF_ranges(phb->hose, np, primary); + primary = 0; + + phb->hose->ops = &pnv_pci_ops; + + /* Setup TCEs */ + phb->dma_dev_setup = pnv_pci_p5ioc2_dma_dev_setup; + pnv_pci_setup_iommu_table(&phb->p5ioc2.iommu_table, + tce_mem, tce_size, 0); +} + +void __init pnv_pci_init_p5ioc2_hub(struct device_node *np) +{ + struct device_node *phbn; + const u64 *prop64; + u64 hub_id; + void *tce_mem; + uint64_t tce_per_phb; + int64_t rc; + int phb_count = 0; + + pr_info("Probing p5ioc2 IO-Hub %s\n", np->full_name); + + prop64 = of_get_property(np, "ibm,opal-hubid", NULL); + if (!prop64) { + pr_err(" Missing \"ibm,opal-hubid\" property !\n"); + return; + } + hub_id = be64_to_cpup(prop64); + pr_info(" HUB-ID : 0x%016llx\n", hub_id); + + /* Currently allocate 16M of TCE memory for every Hub + * + * XXX TODO: Make it chip local if possible + */ + tce_mem = __alloc_bootmem(P5IOC2_TCE_MEMORY, P5IOC2_TCE_MEMORY, + __pa(MAX_DMA_ADDRESS)); + if (!tce_mem) { + pr_err(" Failed to allocate TCE Memory !\n"); + return; + } + pr_debug(" TCE : 0x%016lx..0x%016lx\n", + __pa(tce_mem), __pa(tce_mem) + P5IOC2_TCE_MEMORY - 1); + rc = opal_pci_set_hub_tce_memory(hub_id, __pa(tce_mem), + P5IOC2_TCE_MEMORY); + if (rc != OPAL_SUCCESS) { + pr_err(" Failed to allocate TCE memory, OPAL error %lld\n", rc); + return; + } + + /* Count child PHBs */ + for_each_child_of_node(np, phbn) { + if (of_device_is_compatible(phbn, "ibm,p5ioc2-pcix") || + of_device_is_compatible(phbn, "ibm,p5ioc2-pciex")) + phb_count++; + } + + /* Calculate how much TCE space we can give per PHB */ + tce_per_phb = __rounddown_pow_of_two(P5IOC2_TCE_MEMORY / phb_count); + pr_info(" Allocating %lld MB of TCE memory per PHB\n", + tce_per_phb >> 20); + + /* Initialize PHBs */ + for_each_child_of_node(np, phbn) { + if (of_device_is_compatible(phbn, "ibm,p5ioc2-pcix") || + of_device_is_compatible(phbn, "ibm,p5ioc2-pciex")) { + pnv_pci_init_p5ioc2_phb(phbn, tce_mem, tce_per_phb); + tce_mem += tce_per_phb; + } + } +} diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c new file mode 100644 index 000000000000..746ce5e51208 --- /dev/null +++ b/arch/powerpc/platforms/powernv/pci.c @@ -0,0 +1,286 @@ +/* + * Support PCI/PCIe on PowerNV platforms + * + * Currently supports only P5IOC2 + * + * Copyright 2011 Benjamin Herrenschmidt, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "powernv.h" +#include "pci.h" + + +#define cfg_dbg(fmt...) do { } while(0) +//#define cfg_dbg(fmt...) printk(fmt) + + +static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus, + u32 bdfn) +{ + s64 rc; + u8 fstate; + u16 pcierr; + u32 pe_no; + + /* Get PE# if we support IODA */ + pe_no = phb->bdfn_to_pe ? phb->bdfn_to_pe(phb, bus, bdfn & 0xff) : 0; + + /* Read freeze status */ + rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, &fstate, &pcierr, + NULL); + if (rc) { + pr_warning("PCI %d: Failed to read EEH status for PE#%d," + " err %lld\n", phb->hose->global_number, pe_no, rc); + return; + } + cfg_dbg(" -> EEH check, bdfn=%04x PE%d fstate=%x\n", + bdfn, pe_no, fstate); + if (fstate != 0) { + rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, + OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); + if (rc) { + pr_warning("PCI %d: Failed to clear EEH freeze state" + " for PE#%d, err %lld\n", + phb->hose->global_number, pe_no, rc); + } + } +} + +static int pnv_pci_read_config(struct pci_bus *bus, + unsigned int devfn, + int where, int size, u32 *val) +{ + struct pci_controller *hose = pci_bus_to_host(bus); + struct pnv_phb *phb = hose->private_data; + u32 bdfn = (((uint64_t)bus->number) << 8) | devfn; + s64 rc; + + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + switch (size) { + case 1: { + u8 v8; + rc = opal_pci_config_read_byte(phb->opal_id, bdfn, where, &v8); + *val = (rc == OPAL_SUCCESS) ? v8 : 0xff; + break; + } + case 2: { + u16 v16; + rc = opal_pci_config_read_half_word(phb->opal_id, bdfn, where, + &v16); + *val = (rc == OPAL_SUCCESS) ? v16 : 0xffff; + break; + } + case 4: { + u32 v32; + rc = opal_pci_config_read_word(phb->opal_id, bdfn, where, &v32); + *val = (rc == OPAL_SUCCESS) ? v32 : 0xffffffff; + break; + } + default: + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + cfg_dbg("pnv_pci_read_config bus: %x devfn: %x +%x/%x -> %08x\n", + bus->number, devfn, where, size, *val); + + /* Check if the PHB got frozen due to an error (no response) */ + pnv_pci_config_check_eeh(phb, bus, bdfn); + + return PCIBIOS_SUCCESSFUL; +} + +static int pnv_pci_write_config(struct pci_bus *bus, + unsigned int devfn, + int where, int size, u32 val) +{ + struct pci_controller *hose = pci_bus_to_host(bus); + struct pnv_phb *phb = hose->private_data; + u32 bdfn = (((uint64_t)bus->number) << 8) | devfn; + + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + + cfg_dbg("pnv_pci_write_config bus: %x devfn: %x +%x/%x -> %08x\n", + bus->number, devfn, where, size, val); + switch (size) { + case 1: + opal_pci_config_write_byte(phb->opal_id, bdfn, where, val); + break; + case 2: + opal_pci_config_write_half_word(phb->opal_id, bdfn, where, val); + break; + case 4: + opal_pci_config_write_word(phb->opal_id, bdfn, where, val); + break; + default: + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + /* Check if the PHB got frozen due to an error (no response) */ + pnv_pci_config_check_eeh(phb, bus, bdfn); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops pnv_pci_ops = { + .read = pnv_pci_read_config, + .write = pnv_pci_write_config, +}; + +static int pnv_tce_build(struct iommu_table *tbl, long index, long npages, + unsigned long uaddr, enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + u64 proto_tce; + u64 *tcep; + u64 rpn; + + proto_tce = TCE_PCI_READ; // Read allowed + + if (direction != DMA_TO_DEVICE) + proto_tce |= TCE_PCI_WRITE; + + tcep = ((u64 *)tbl->it_base) + index; + + while (npages--) { + /* can't move this out since we might cross LMB boundary */ + rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; + *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; + + uaddr += TCE_PAGE_SIZE; + tcep++; + } + return 0; +} + +static void pnv_tce_free(struct iommu_table *tbl, long index, long npages) +{ + u64 *tcep = ((u64 *)tbl->it_base) + index; + + while (npages--) + *(tcep++) = 0; +} + +void pnv_pci_setup_iommu_table(struct iommu_table *tbl, + void *tce_mem, u64 tce_size, + u64 dma_offset) +{ + tbl->it_blocksize = 16; + tbl->it_base = (unsigned long)tce_mem; + tbl->it_offset = dma_offset >> IOMMU_PAGE_SHIFT; + tbl->it_index = 0; + tbl->it_size = tce_size >> 3; + tbl->it_busno = 0; + tbl->it_type = TCE_PCI; +} + +static struct iommu_table * __devinit +pnv_pci_setup_bml_iommu(struct pci_controller *hose) +{ + struct iommu_table *tbl; + const __be64 *basep; + const __be32 *sizep; + + basep = of_get_property(hose->dn, "linux,tce-base", NULL); + sizep = of_get_property(hose->dn, "linux,tce-size", NULL); + if (basep == NULL || sizep == NULL) { + pr_err("PCI: %s has missing tce entries !\n", hose->dn->full_name); + return NULL; + } + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, hose->node); + if (WARN_ON(!tbl)) + return NULL; + pnv_pci_setup_iommu_table(tbl, __va(be64_to_cpup(basep)), + be32_to_cpup(sizep), 0); + iommu_init_table(tbl, hose->node); + return tbl; +} + +static void __devinit pnv_pci_dma_fallback_setup(struct pci_controller *hose, + struct pci_dev *pdev) +{ + struct device_node *np = pci_bus_to_OF_node(hose->bus); + struct pci_dn *pdn; + + if (np == NULL) + return; + pdn = PCI_DN(np); + if (!pdn->iommu_table) + pdn->iommu_table = pnv_pci_setup_bml_iommu(hose); + if (!pdn->iommu_table) + return; + set_iommu_table_base(&pdev->dev, pdn->iommu_table); +} + +static void __devinit pnv_pci_dma_dev_setup(struct pci_dev *pdev) +{ + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + struct pnv_phb *phb = hose->private_data; + + /* If we have no phb structure, try to setup a fallback based on + * the device-tree (RTAS PCI for example) + */ + if (phb && phb->dma_dev_setup) + phb->dma_dev_setup(phb, pdev); + else + pnv_pci_dma_fallback_setup(hose, pdev); +} + +void __init pnv_pci_init(void) +{ + struct device_node *np; + + pci_set_flags(PCI_CAN_SKIP_ISA_ALIGN); + + /* We do not want to just probe */ + pci_probe_only = 0; + + /* OPAL absent, try POPAL first then RTAS detection of PHBs */ + if (!firmware_has_feature(FW_FEATURE_OPAL)) { +#ifdef CONFIG_PPC_POWERNV_RTAS + init_pci_config_tokens(); + find_and_init_phbs(); +#endif /* CONFIG_PPC_POWERNV_RTAS */ + } else { + /* OPAL is here, do our normal stuff */ + + /* Look for p5ioc2 IO-Hubs */ + for_each_compatible_node(np, NULL, "ibm,p5ioc2") + pnv_pci_init_p5ioc2_hub(np); + } + + /* Setup the linkage between OF nodes and PHBs */ + pci_devs_phb_init(); + + /* Configure IOMMU DMA hooks */ + ppc_md.pci_dma_dev_setup = pnv_pci_dma_dev_setup; + ppc_md.tce_build = pnv_tce_build; + ppc_md.tce_free = pnv_tce_free; + set_pci_dma_ops(&dma_iommu_ops); + +} diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h new file mode 100644 index 000000000000..6730a10d7369 --- /dev/null +++ b/arch/powerpc/platforms/powernv/pci.h @@ -0,0 +1,38 @@ +#ifndef __POWERNV_PCI_H +#define __POWERNV_PCI_H + +struct pci_dn; + +enum pnv_phb_type { + PNV_PHB_P5IOC2, + PNV_PHB_IODA1, + PNV_PHB_IODA2, +}; + +struct pnv_phb { + struct pci_controller *hose; + enum pnv_phb_type type; + u64 opal_id; + void __iomem *regs; + spinlock_t lock; + + void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev); + void (*fixup_phb)(struct pci_controller *hose); + u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn); + + union { + struct { + struct iommu_table iommu_table; + } p5ioc2; + }; +}; + +extern struct pci_ops pnv_pci_ops; + +extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl, + void *tce_mem, u64 tce_size, + u64 dma_offset); +extern void pnv_pci_init_p5ioc2_hub(struct device_node *np); + + +#endif /* __POWERNV_PCI_H */ diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h index 35b716008cd3..8a9df7f9667e 100644 --- a/arch/powerpc/platforms/powernv/powernv.h +++ b/arch/powerpc/platforms/powernv/powernv.h @@ -7,4 +7,10 @@ extern void pnv_smp_init(void); static inline void pnv_smp_init(void) { } #endif +#ifdef CONFIG_PCI +extern void pnv_pci_init(void); +#else +static inline void pnv_pci_init(void) { } +#endif + #endif /* _POWERNV_H */ diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index f0242f3fd3e6..467bd4ac6824 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -40,7 +40,8 @@ static void __init pnv_setup_arch(void) /* Initialize SMP */ pnv_smp_init(); - /* XXX PCI */ + /* Setup PCI */ + pnv_pci_init(); /* Setup RTC and NVRAM callbacks */ if (firmware_has_feature(FW_FEATURE_OPAL)) From c1a2562ac5edcb3965760f4a37368122d85657af Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:45:06 +0000 Subject: [PATCH 0430/1596] powerpc/powernv: Implement MSI support for p5ioc2 PCIe This implements support for MSIs on p5ioc2 PHBs. We only support MSIs on the PCIe PHBs, not the PCI-X ones as the later hasn't been properly verified in HW. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/pci-p5ioc2.c | 49 +++++++++ arch/powerpc/platforms/powernv/pci.c | 109 ++++++++++++++++++++ arch/powerpc/platforms/powernv/pci.h | 10 ++ 3 files changed, 168 insertions(+) diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c index afabc2bcae45..4c80f7c77d56 100644 --- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c +++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,51 @@ */ #define P5IOC2_TCE_MEMORY 0x01000000 +#ifdef CONFIG_PCI_MSI +static int pnv_pci_p5ioc2_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, + unsigned int hwirq, unsigned int is_64, + struct msi_msg *msg) +{ + if (WARN_ON(!is_64)) + return -ENXIO; + msg->data = hwirq - phb->msi_base; + msg->address_hi = 0x10000000; + msg->address_lo = 0; + + return 0; +} + +static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) +{ + unsigned int bmap_size; + const __be32 *prop = of_get_property(phb->hose->dn, + "ibm,opal-msi-ranges", NULL); + if (!prop) + return; + + /* Don't do MSI's on p5ioc2 PCI-X are they are not properly + * verified in HW + */ + if (of_device_is_compatible(phb->hose->dn, "ibm,p5ioc2-pcix")) + return; + phb->msi_base = be32_to_cpup(prop); + phb->msi_count = be32_to_cpup(prop + 1); + bmap_size = BITS_TO_LONGS(phb->msi_count) * sizeof(unsigned long); + phb->msi_map = zalloc_maybe_bootmem(bmap_size, GFP_KERNEL); + if (!phb->msi_map) { + pr_err("PCI %d: Failed to allocate MSI bitmap !\n", + phb->hose->global_number); + return; + } + phb->msi_setup = pnv_pci_p5ioc2_msi_setup; + phb->msi32_support = 0; + pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", + phb->msi_count, phb->msi_base); +} +#else +static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { } +#endif /* CONFIG_PCI_MSI */ + static void __devinit pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev) { @@ -117,6 +163,9 @@ static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, phb->hose->ops = &pnv_pci_ops; + /* Setup MSI support */ + pnv_pci_init_p5ioc2_msis(phb); + /* Setup TCEs */ phb->dma_dev_setup = pnv_pci_p5ioc2_dma_dev_setup; pnv_pci_setup_iommu_table(&phb->p5ioc2.iommu_table, diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 746ce5e51208..5c175519cf9e 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,108 @@ #define cfg_dbg(fmt...) do { } while(0) //#define cfg_dbg(fmt...) printk(fmt) +#ifdef CONFIG_PCI_MSI +static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type) +{ + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + struct pnv_phb *phb = hose->private_data; + + return (phb && phb->msi_map) ? 0 : -ENODEV; +} + +static unsigned int pnv_get_one_msi(struct pnv_phb *phb) +{ + unsigned int id; + + spin_lock(&phb->lock); + id = find_next_zero_bit(phb->msi_map, phb->msi_count, phb->msi_next); + if (id >= phb->msi_count && phb->msi_next) + id = find_next_zero_bit(phb->msi_map, phb->msi_count, 0); + if (id >= phb->msi_count) { + spin_unlock(&phb->lock); + return 0; + } + __set_bit(id, phb->msi_map); + spin_unlock(&phb->lock); + return id + phb->msi_base; +} + +static void pnv_put_msi(struct pnv_phb *phb, unsigned int hwirq) +{ + unsigned int id; + + if (WARN_ON(hwirq < phb->msi_base || + hwirq >= (phb->msi_base + phb->msi_count))) + return; + id = hwirq - phb->msi_base; + spin_lock(&phb->lock); + __clear_bit(id, phb->msi_map); + spin_unlock(&phb->lock); +} + +static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) +{ + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + struct pnv_phb *phb = hose->private_data; + struct msi_desc *entry; + struct msi_msg msg; + unsigned int hwirq, virq; + int rc; + + if (WARN_ON(!phb)) + return -ENODEV; + + list_for_each_entry(entry, &pdev->msi_list, list) { + if (!entry->msi_attrib.is_64 && !phb->msi32_support) { + pr_warn("%s: Supports only 64-bit MSIs\n", + pci_name(pdev)); + return -ENXIO; + } + hwirq = pnv_get_one_msi(phb); + if (!hwirq) { + pr_warn("%s: Failed to find a free MSI\n", + pci_name(pdev)); + return -ENOSPC; + } + virq = irq_create_mapping(NULL, hwirq); + if (virq == NO_IRQ) { + pr_warn("%s: Failed to map MSI to linux irq\n", + pci_name(pdev)); + pnv_put_msi(phb, hwirq); + return -ENOMEM; + } + rc = phb->msi_setup(phb, pdev, hwirq, entry->msi_attrib.is_64, + &msg); + if (rc) { + pr_warn("%s: Failed to setup MSI\n", pci_name(pdev)); + irq_dispose_mapping(virq); + pnv_put_msi(phb, hwirq); + return rc; + } + irq_set_msi_desc(virq, entry); + write_msi_msg(virq, &msg); + } + return 0; +} + +static void pnv_teardown_msi_irqs(struct pci_dev *pdev) +{ + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + struct pnv_phb *phb = hose->private_data; + struct msi_desc *entry; + + if (WARN_ON(!phb)) + return; + + list_for_each_entry(entry, &pdev->msi_list, list) { + if (entry->irq == NO_IRQ) + continue; + irq_set_msi_desc(entry->irq, NULL); + pnv_put_msi(phb, virq_to_hw(entry->irq)); + irq_dispose_mapping(entry->irq); + } +} +#endif /* CONFIG_PCI_MSI */ static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus, u32 bdfn) @@ -283,4 +386,10 @@ void __init pnv_pci_init(void) ppc_md.tce_free = pnv_tce_free; set_pci_dma_ops(&dma_iommu_ops); + /* Configure MSIs */ +#ifdef CONFIG_PCI_MSI + ppc_md.msi_check_device = pnv_msi_check_device; + ppc_md.setup_msi_irqs = pnv_setup_msi_irqs; + ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs; +#endif } diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 6730a10d7369..d4dbc4950936 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -16,6 +16,16 @@ struct pnv_phb { void __iomem *regs; spinlock_t lock; +#ifdef CONFIG_PCI_MSI + unsigned long *msi_map; + unsigned int msi_base; + unsigned int msi_count; + unsigned int msi_next; + unsigned int msi32_support; +#endif + int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev, + unsigned int hwirq, unsigned int is_64, + struct msi_msg *msg); void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev); void (*fixup_phb)(struct pci_controller *hose); u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn); From 82ba129baeb1ff72e75d93e70534ba50312153f3 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2011 17:45:07 +0000 Subject: [PATCH 0431/1596] powerpc/powernv: Handle PCI-X/PCIe reset delay The firmware doesn't wait after lifting the PCI reset. However it does timestamp it in the device tree. We use that to ensure we wait long enough (3s is our current arbitrary setting) from that timestamp to actually probing the bus. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/pci.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 5c175519cf9e..85bb66d7f933 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -35,6 +35,8 @@ #include "powernv.h" #include "pci.h" +/* Delay in usec */ +#define PCI_RESET_DELAY_US 3000000 #define cfg_dbg(fmt...) do { } while(0) //#define cfg_dbg(fmt...) printk(fmt) @@ -354,6 +356,35 @@ static void __devinit pnv_pci_dma_dev_setup(struct pci_dev *pdev) pnv_pci_dma_fallback_setup(hose, pdev); } +static int pnv_pci_probe_mode(struct pci_bus *bus) +{ + struct pci_controller *hose = pci_bus_to_host(bus); + const __be64 *tstamp; + u64 now, target; + + + /* We hijack this as a way to ensure we have waited long + * enough since the reset was lifted on the PCI bus + */ + if (bus != hose->bus) + return PCI_PROBE_NORMAL; + tstamp = of_get_property(hose->dn, "reset-clear-timestamp", NULL); + if (!tstamp || !*tstamp) + return PCI_PROBE_NORMAL; + + now = mftb() / tb_ticks_per_usec; + target = (be64_to_cpup(tstamp) / tb_ticks_per_usec) + + PCI_RESET_DELAY_US; + + pr_devel("pci %04d: Reset target: 0x%llx now: 0x%llx\n", + hose->global_number, target, now); + + if (now < target) + msleep((target - now + 999) / 1000); + + return PCI_PROBE_NORMAL; +} + void __init pnv_pci_init(void) { struct device_node *np; @@ -384,6 +415,7 @@ void __init pnv_pci_init(void) ppc_md.pci_dma_dev_setup = pnv_pci_dma_dev_setup; ppc_md.tce_build = pnv_tce_build; ppc_md.tce_free = pnv_tce_free; + ppc_md.pci_probe_mode = pnv_pci_probe_mode; set_pci_dma_ops(&dma_iommu_ops); /* Configure MSIs */ From a120db06c3f435c37d028b6e5a1968dad06b7df0 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Thu, 8 Sep 2011 21:12:06 +0000 Subject: [PATCH 0432/1596] perf events, powerpc: Add POWER7 stalled-cycles-frontend/backend events perf events, powerpc: Add POWER7 stalled-cycles-frontend/backend events Extent the POWER7 PMU driver with definitions for generic front-end and back-end stall events. As explained in Ingo's original comment(8f62242246351b5a4bc0c1f00c0c7003edea128a ), the exact definitions of the stall events are very much processor specific as different things mean different in their respective instruction pipeline. These two Power7 raw events are the closest approximation to the concept detailed in Ingo's comment. [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x100f8, /* GCT_NOSLOT_CYC */ It means cycles when the Global Completion Table has no slots from this thread [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x4000a, /* CMPLU_STALL */ It means no groups completed and GCT not empty for this thread Signed-off-by: Anshuman Khandual Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/power7-pmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/kernel/power7-pmu.c index de83d6060dda..1251e4d7e262 100644 --- a/arch/powerpc/kernel/power7-pmu.c +++ b/arch/powerpc/kernel/power7-pmu.c @@ -297,6 +297,8 @@ static void power7_disable_pmc(unsigned int pmc, unsigned long mmcr[]) static int power7_generic_events[] = { [PERF_COUNT_HW_CPU_CYCLES] = 0x1e, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x100f8, /* GCT_NOSLOT_CYC */ + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x4000a, /* CMPLU_STALL */ [PERF_COUNT_HW_INSTRUCTIONS] = 2, [PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880, /* LD_REF_L1_LSU*/ [PERF_COUNT_HW_CACHE_MISSES] = 0x400f0, /* LD_MISS_L1 */ From 463894705e4089d0ff69e7d877312d496ac70e5b Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 15 Sep 2011 03:06:30 -0700 Subject: [PATCH 0433/1596] dmaengine: delete redundant chan_id and chancnt initialization in dma drivers dma_async_device_register will re-init chan_id and chancnt, so whatever chan_id and chancnt are set in drivers, they will be re-written by dma_async_device_register. Cc: Nicolas Ferre Cc: Viresh Kumar Cc: Vinod Koul Cc: Piotr Ziecik Cc: Yong Wang Cc: Jaswinder Singh Cc: Pelagicore AB Signed-off-by: Barry Song Acked-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 5 ++--- drivers/dma/dw_dmac.c | 5 ++--- drivers/dma/intel_mid_dma.c | 2 -- drivers/dma/mpc512x_dma.c | 1 - drivers/dma/pch_dma.c | 2 -- drivers/dma/pl330.c | 2 -- drivers/dma/timb_dma.c | 3 +-- 7 files changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 3b99dc62874b..fcfa0a8b5c59 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1268,12 +1268,11 @@ static int __init at_dma_probe(struct platform_device *pdev) /* initialize channels related values */ INIT_LIST_HEAD(&atdma->dma_common.channels); - for (i = 0; i < pdata->nr_channels; i++, atdma->dma_common.chancnt++) { + for (i = 0; i < pdata->nr_channels; i++) { struct at_dma_chan *atchan = &atdma->chan[i]; atchan->chan_common.device = &atdma->dma_common; atchan->chan_common.cookie = atchan->completed_cookie = 1; - atchan->chan_common.chan_id = i; list_add_tail(&atchan->chan_common.device_node, &atdma->dma_common.channels); @@ -1314,7 +1313,7 @@ static int __init at_dma_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s), %d channels\n", dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "", dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ? "slave " : "", - atdma->dma_common.chancnt); + pdata->nr_channels); dma_async_device_register(&atdma->dma_common); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 4d180ca9a1d8..9bfd6d360718 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1407,12 +1407,11 @@ static int __init dw_probe(struct platform_device *pdev) dw->all_chan_mask = (1 << pdata->nr_channels) - 1; INIT_LIST_HEAD(&dw->dma.channels); - for (i = 0; i < pdata->nr_channels; i++, dw->dma.chancnt++) { + for (i = 0; i < pdata->nr_channels; i++) { struct dw_dma_chan *dwc = &dw->chan[i]; dwc->chan.device = &dw->dma; dwc->chan.cookie = dwc->completed = 1; - dwc->chan.chan_id = i; if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING) list_add_tail(&dwc->chan.device_node, &dw->dma.channels); @@ -1468,7 +1467,7 @@ static int __init dw_probe(struct platform_device *pdev) dma_writel(dw, CFG, DW_CFG_DMA_EN); printk(KERN_INFO "%s: DesignWare DMA Controller, %d channels\n", - dev_name(&pdev->dev), dw->dma.chancnt); + dev_name(&pdev->dev), pdata->nr_channels); dma_async_device_register(&dw->dma); diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 8a3fdd87db97..cf74a664c5e0 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -1114,7 +1114,6 @@ static int mid_setup_dma(struct pci_dev *pdev) midch->chan.device = &dma->common; midch->chan.cookie = 1; - midch->chan.chan_id = i; midch->ch_id = dma->chan_base + i; pr_debug("MDMA:Init CH %d, ID %d\n", i, midch->ch_id); @@ -1150,7 +1149,6 @@ static int mid_setup_dma(struct pci_dev *pdev) dma_cap_set(DMA_SLAVE, dma->common.cap_mask); dma_cap_set(DMA_PRIVATE, dma->common.cap_mask); dma->common.dev = &pdev->dev; - dma->common.chancnt = dma->max_chan; dma->common.device_alloc_chan_resources = intel_mid_dma_alloc_chan_resources; diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index b9bae94f2015..8ba4edc6185e 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -741,7 +741,6 @@ static int __devinit mpc_dma_probe(struct platform_device *op) mchan = &mdma->channels[i]; mchan->chan.device = dma; - mchan->chan.chan_id = i; mchan->chan.cookie = 1; mchan->completed_cookie = mchan->chan.cookie; diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index 1ac8d4b580b7..5b65362024fd 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -926,7 +926,6 @@ static int __devinit pch_dma_probe(struct pci_dev *pdev, } pd->dma.dev = &pdev->dev; - pd->dma.chancnt = nr_channels; INIT_LIST_HEAD(&pd->dma.channels); @@ -935,7 +934,6 @@ static int __devinit pch_dma_probe(struct pci_dev *pdev, pd_chan->chan.device = &pd->dma; pd_chan->chan.cookie = 1; - pd_chan->chan.chan_id = i; pd_chan->membase = ®s->desc[i]; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 00eee59e8b33..7f86e7df7da1 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -747,11 +747,9 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&pch->lock); pch->pl330_chid = NULL; pch->chan.device = pd; - pch->chan.chan_id = i; pch->dmac = pdmac; /* Add the channel to the DMAC list */ - pd->chancnt++; list_add_tail(&pch->chan.device_node, &pd->channels); } diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index f69f90a61873..6dbdf451128e 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -753,7 +753,7 @@ static int __devinit td_probe(struct platform_device *pdev) INIT_LIST_HEAD(&td->dma.channels); - for (i = 0; i < pdata->nr_channels; i++, td->dma.chancnt++) { + for (i = 0; i < pdata->nr_channels; i++) { struct timb_dma_chan *td_chan = &td->channels[i]; struct timb_dma_platform_data_channel *pchan = pdata->channels + i; @@ -767,7 +767,6 @@ static int __devinit td_probe(struct platform_device *pdev) td_chan->chan.device = &td->dma; td_chan->chan.cookie = 1; - td_chan->chan.chan_id = i; spin_lock_init(&td_chan->lock); INIT_LIST_HEAD(&td_chan->active_list); INIT_LIST_HEAD(&td_chan->queue); From 536137bc9ff1738a7bee9b31047a7cd56860180e Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Fri, 26 Aug 2011 11:03:03 +0900 Subject: [PATCH 0434/1596] gpio/s3c24xx: move gpio driver into drivers/gpio/ Cc: Ben Dooks Acked-by: Grant Likely Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c2410/Kconfig | 6 -- arch/arm/mach-s3c2410/Makefile | 1 - arch/arm/mach-s3c2412/Kconfig | 1 - arch/arm/mach-s3c2412/Makefile | 1 - arch/arm/mach-s3c2440/Kconfig | 2 - arch/arm/plat-s3c24xx/Makefile | 2 - arch/arm/plat-s3c24xx/gpio.c | 96 ------------------- drivers/gpio/Kconfig | 4 + drivers/gpio/Makefile | 1 + .../gpiolib.c => drivers/gpio/gpio-s3c24xx.c | 70 ++++++++++++-- 10 files changed, 67 insertions(+), 117 deletions(-) delete mode 100644 arch/arm/plat-s3c24xx/gpio.c rename arch/arm/plat-s3c24xx/gpiolib.c => drivers/gpio/gpio-s3c24xx.c (78%) diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 7245a55795dc..3700cf32af0f 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -8,7 +8,6 @@ config CPU_S3C2410 select CPU_ARM920T select S3C_GPIO_PULL_UP select S3C2410_CLOCK - select S3C2410_GPIO select CPU_LLSERIAL_S3C2410 select S3C2410_PM if PM select S3C2410_CPUFREQ if CPU_FREQ_S3C24XX @@ -28,11 +27,6 @@ config S3C2410_PM help Power Management code common to S3C2410 and better -config S3C2410_GPIO - bool - help - GPIO code for S3C2410 and similar processors - config SIMTEC_NOR bool help diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 81695353d8f4..782fd81144e9 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_CPU_S3C2410) += s3c2410.o obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o -obj-$(CONFIG_S3C2410_GPIO) += gpio.o obj-$(CONFIG_S3C2410_CPUFREQ) += cpu-freq.o obj-$(CONFIG_S3C2410_PLLTABLE) += pll.o diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig index c2cf4e569989..b8b9029e9f2d 100644 --- a/arch/arm/mach-s3c2412/Kconfig +++ b/arch/arm/mach-s3c2412/Kconfig @@ -9,7 +9,6 @@ config CPU_S3C2412 select CPU_LLSERIAL_S3C2440 select S3C2412_PM if PM select S3C2412_DMA if S3C2410_DMA - select S3C2410_GPIO help Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile index 6c48a91ea39e..7e4d95fa8a97 100644 --- a/arch/arm/mach-s3c2412/Makefile +++ b/arch/arm/mach-s3c2412/Makefile @@ -12,7 +12,6 @@ obj- := obj-$(CONFIG_CPU_S3C2412) += s3c2412.o obj-$(CONFIG_CPU_S3C2412) += irq.o obj-$(CONFIG_CPU_S3C2412) += clock.o -obj-$(CONFIG_CPU_S3C2412) += gpio.o obj-$(CONFIG_S3C2412_DMA) += dma.o obj-$(CONFIG_S3C2412_PM) += pm.o obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep.o diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig index 50825a3f91cc..c461fb8e15c0 100644 --- a/arch/arm/mach-s3c2440/Kconfig +++ b/arch/arm/mach-s3c2440/Kconfig @@ -8,7 +8,6 @@ config CPU_S3C2440 select S3C_GPIO_PULL_UP select S3C2410_CLOCK select S3C2410_PM if PM - select S3C2410_GPIO select S3C2440_DMA if S3C2410_DMA select CPU_S3C244X select CPU_LLSERIAL_S3C2440 @@ -20,7 +19,6 @@ config CPU_S3C2442 select CPU_ARM920T select S3C_GPIO_PULL_DOWN select S3C2410_CLOCK - select S3C2410_GPIO select S3C2410_PM if PM select CPU_S3C244X select CPU_LLSERIAL_S3C2440 diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile index 0291bd6e236e..e4f46495ed30 100644 --- a/arch/arm/plat-s3c24xx/Makefile +++ b/arch/arm/plat-s3c24xx/Makefile @@ -15,8 +15,6 @@ obj- := obj-y += cpu.o obj-y += irq.o obj-y += devs.o -obj-y += gpio.o -obj-y += gpiolib.o obj-y += clock.o obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c deleted file mode 100644 index 2f3d7c089dfa..000000000000 --- a/arch/arm/plat-s3c24xx/gpio.c +++ /dev/null @@ -1,96 +0,0 @@ -/* linux/arch/arm/plat-s3c24xx/gpio.c - * - * Copyright (c) 2004-2010 Simtec Electronics - * Ben Dooks - * - * S3C24XX GPIO support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -/* gpiolib wrappers until these are totally eliminated */ - -void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) -{ - int ret; - - WARN_ON(to); /* should be none of these left */ - - if (!to) { - /* if pull is enabled, try first with up, and if that - * fails, try using down */ - - ret = s3c_gpio_setpull(pin, S3C_GPIO_PULL_UP); - if (ret) - s3c_gpio_setpull(pin, S3C_GPIO_PULL_DOWN); - } else { - s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE); - } -} -EXPORT_SYMBOL(s3c2410_gpio_pullup); - -void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) -{ - /* do this via gpiolib until all users removed */ - - gpio_request(pin, "temporary"); - gpio_set_value(pin, to); - gpio_free(pin); -} - -EXPORT_SYMBOL(s3c2410_gpio_setpin); - -unsigned int s3c2410_gpio_getpin(unsigned int pin) -{ - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); - unsigned long offs = pin - chip->chip.base; - - return __raw_readl(chip->base + 0x04) & (1<< offs); -} - -EXPORT_SYMBOL(s3c2410_gpio_getpin); - -unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) -{ - unsigned long flags; - unsigned long misccr; - - local_irq_save(flags); - misccr = __raw_readl(S3C24XX_MISCCR); - misccr &= ~clear; - misccr ^= change; - __raw_writel(misccr, S3C24XX_MISCCR); - local_irq_restore(flags); - - return misccr; -} - -EXPORT_SYMBOL(s3c2410_modify_misccr); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d539efd96d4b..5654e1b082af 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -135,6 +135,10 @@ config GPIO_PLAT_SAMSUNG def_bool y depends on SAMSUNG_GPIOLIB_4BIT +config GPIO_S3C24XX + def_bool y + depends on PLAT_S3C24XX + config GPIO_S5PC100 def_bool y depends on CPU_S5PC100 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9588948c96f0..c7f1c00986c9 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o +obj-$(CONFIG_GPIO_S3C24XX) += gpio-s3c24xx.o obj-$(CONFIG_GPIO_S5PC100) += gpio-s5pc100.o obj-$(CONFIG_GPIO_S5PV210) += gpio-s5pv210.o diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/drivers/gpio/gpio-s3c24xx.c similarity index 78% rename from arch/arm/plat-s3c24xx/gpiolib.c rename to drivers/gpio/gpio-s3c24xx.c index 243b6411050d..ff6103130fe8 100644 --- a/arch/arm/plat-s3c24xx/gpiolib.c +++ b/drivers/gpio/gpio-s3c24xx.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s3c24xx/gpiolib.c - * +/* * Copyright (c) 2008-2010 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks @@ -19,16 +18,17 @@ #include #include #include +#include + +#include +#include +#include #include #include #include -#include -#include #include -#include - static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset) { return -EINVAL; @@ -210,7 +210,6 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { }, }; - static __init int s3c24xx_gpiolib_init(void) { struct s3c_gpio_chip *chip = s3c24xx_gpios; @@ -225,5 +224,60 @@ static __init int s3c24xx_gpiolib_init(void) return 0; } - core_initcall(s3c24xx_gpiolib_init); + +/* gpiolib wrappers until these are totally eliminated */ + +void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) +{ + int ret; + + WARN_ON(to); /* should be none of these left */ + + if (!to) { + /* if pull is enabled, try first with up, and if that + * fails, try using down */ + + ret = s3c_gpio_setpull(pin, S3C_GPIO_PULL_UP); + if (ret) + s3c_gpio_setpull(pin, S3C_GPIO_PULL_DOWN); + } else { + s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE); + } +} +EXPORT_SYMBOL(s3c2410_gpio_pullup); + +void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) +{ + /* do this via gpiolib until all users removed */ + + gpio_request(pin, "temporary"); + gpio_set_value(pin, to); + gpio_free(pin); +} +EXPORT_SYMBOL(s3c2410_gpio_setpin); + +unsigned int s3c2410_gpio_getpin(unsigned int pin) +{ + struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); + unsigned long offs = pin - chip->chip.base; + + return __raw_readl(chip->base + 0x04) & (1<< offs); +} +EXPORT_SYMBOL(s3c2410_gpio_getpin); + +unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) +{ + unsigned long flags; + unsigned long misccr; + + local_irq_save(flags); + misccr = __raw_readl(S3C24XX_MISCCR); + misccr &= ~clear; + misccr ^= change; + __raw_writel(misccr, S3C24XX_MISCCR); + local_irq_restore(flags); + + return misccr; +} +EXPORT_SYMBOL(s3c2410_modify_misccr); From ec080059c1ce7bfdc8453bf4f3328ac0315a66a1 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Fri, 26 Aug 2011 11:06:25 +0900 Subject: [PATCH 0435/1596] gpio/s3c64xx: move gpio driver into drivers/gpio/ Cc: Ben Dooks Acked-by: Grant Likely Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/Makefile | 1 - drivers/gpio/Kconfig | 4 ++++ drivers/gpio/Makefile | 1 + .../arm/mach-s3c64xx/gpiolib.c => drivers/gpio/gpio-s3c64xx.c | 3 +-- 4 files changed, 6 insertions(+), 3 deletions(-) rename arch/arm/mach-s3c64xx/gpiolib.c => drivers/gpio/gpio-s3c64xx.c (99%) diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 61b4034a0c22..f0102d7b531b 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -13,7 +13,6 @@ obj- := # Core files obj-y += cpu.o obj-y += clock.o -obj-y += gpiolib.o # Core support for S3C6400 system diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5654e1b082af..6368730a2e58 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -139,6 +139,10 @@ config GPIO_S3C24XX def_bool y depends on PLAT_S3C24XX +config GPIO_S3C64XX + def_bool y + depends on ARCH_S3C64XX + config GPIO_S5PC100 def_bool y depends on CPU_S5PC100 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c7f1c00986c9..8c1fb23285cb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o obj-$(CONFIG_GPIO_S3C24XX) += gpio-s3c24xx.o +obj-$(CONFIG_GPIO_S3C64XX) += gpio-s3c64xx.o obj-$(CONFIG_GPIO_S5PC100) += gpio-s5pc100.o obj-$(CONFIG_GPIO_S5PV210) += gpio-s5pv210.o diff --git a/arch/arm/mach-s3c64xx/gpiolib.c b/drivers/gpio/gpio-s3c64xx.c similarity index 99% rename from arch/arm/mach-s3c64xx/gpiolib.c rename to drivers/gpio/gpio-s3c64xx.c index 92b09085caaa..b4f1c8204f03 100644 --- a/arch/arm/mach-s3c64xx/gpiolib.c +++ b/drivers/gpio/gpio-s3c64xx.c @@ -1,5 +1,4 @@ -/* arch/arm/plat-s3c64xx/gpiolib.c - * +/* * Copyright 2008 Openmoko, Inc. * Copyright 2008 Simtec Electronics * Ben Dooks From c4b3fd38dfb677d7a3997527c9cbdc21b81424a3 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Fri, 26 Aug 2011 11:07:26 +0900 Subject: [PATCH 0436/1596] gpio/s5p64x0: move gpio driver into drivers/gpio/ Acked-by: Grant Likely Signed-off-by: Kukjin Kim --- arch/arm/mach-s5p64x0/Makefile | 2 +- drivers/gpio/Kconfig | 4 ++++ drivers/gpio/Makefile | 1 + .../arm/mach-s5p64x0/gpiolib.c => drivers/gpio/gpio-s5p64x0.c | 3 +-- 4 files changed, 7 insertions(+), 3 deletions(-) rename arch/arm/mach-s5p64x0/gpiolib.c => drivers/gpio/gpio-s5p64x0.c (99%) diff --git a/arch/arm/mach-s5p64x0/Makefile b/arch/arm/mach-s5p64x0/Makefile index 5f6afdf067ed..5b9495538839 100644 --- a/arch/arm/mach-s5p64x0/Makefile +++ b/arch/arm/mach-s5p64x0/Makefile @@ -12,7 +12,7 @@ obj- := # Core support for S5P64X0 system -obj-$(CONFIG_ARCH_S5P64X0) += cpu.o init.o clock.o dma.o gpiolib.o +obj-$(CONFIG_ARCH_S5P64X0) += cpu.o init.o clock.o dma.o obj-$(CONFIG_ARCH_S5P64X0) += setup-i2c0.o irq-eint.o obj-$(CONFIG_CPU_S5P6440) += clock-s5p6440.o obj-$(CONFIG_CPU_S5P6450) += clock-s5p6450.o diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6368730a2e58..5eb29bc18a56 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -143,6 +143,10 @@ config GPIO_S3C64XX def_bool y depends on ARCH_S3C64XX +config GPIO_S5P64X0 + def_bool y + depends on ARCH_S5P64X0 + config GPIO_S5PC100 def_bool y depends on CPU_S5PC100 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 8c1fb23285cb..10f3bbf0eceb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o obj-$(CONFIG_GPIO_S3C24XX) += gpio-s3c24xx.o obj-$(CONFIG_GPIO_S3C64XX) += gpio-s3c64xx.o +obj-$(CONFIG_GPIO_S5P64X0) += gpio-s5p64x0.o obj-$(CONFIG_GPIO_S5PC100) += gpio-s5pc100.o obj-$(CONFIG_GPIO_S5PV210) += gpio-s5pv210.o diff --git a/arch/arm/mach-s5p64x0/gpiolib.c b/drivers/gpio/gpio-s5p64x0.c similarity index 99% rename from arch/arm/mach-s5p64x0/gpiolib.c rename to drivers/gpio/gpio-s5p64x0.c index e7fb3b004e77..96e816f5cc95 100644 --- a/arch/arm/mach-s5p64x0/gpiolib.c +++ b/drivers/gpio/gpio-s5p64x0.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/mach-s5p64x0/gpiolib.c - * +/* * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. * http://www.samsung.com * From f8de8f4ce2a83ccf7571ee13d41d02a9040797f9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 30 Aug 2011 15:08:24 +0800 Subject: [PATCH 0437/1596] dmaengine i.MX DMA/SDMA: add missing include of linux/module.h Add missing include of linux/module.h to fix build error. Signed-off-by: Axel Lin Acked-by: Wolfram Sang Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 1 + drivers/dma/imx-sdma.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index d99f71c356b5..d746899f36e1 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -14,6 +14,7 @@ * http://www.gnu.org/copyleft/gpl.html */ #include +#include #include #include #include diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index b5cc27dc9a51..eab1fe71259e 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include From 1b39d5f2cc5c28085bbf48db80bf704ab4dedda9 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Tue, 30 Aug 2011 20:39:08 +0900 Subject: [PATCH 0438/1596] gpio/samsung: gpio-samsung.c to support Samsung GPIOs This patch adds support for Samsung GPIOs with one gpio driver and removes old GPIO drivers which are drivers/gpio-s3c24xx.c, gpio-s3c64xx.c, gpio-s5p64x0.c, gpio-s5pc100.c, gpio-s5pv210.c, gpio-exynos4.c, gpio-plat-samsung.c, plat-samsung/gpio-config.c and gpio.c to support each Samsung SoCs before. Because the gpio-samsung.c can replace old Samsung GPIO drivers. Basically, the gpio-samsung.c has been made by their merging and removing duplicated definitions. Note: gpio-samsung.c includes some SoC dependent codes and it will be replaced next time. Cc: Ben Dooks Acked-by: Grant Likely [kgene.kim@samsung.com: squash the removing and adding patches] [kgene.kim@samsung.com: fixes bug during to register of gpio_chips] Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/Makefile | 2 - arch/arm/plat-samsung/gpio-config.c | 431 ----- arch/arm/plat-samsung/gpio.c | 167 -- drivers/gpio/Kconfig | 28 - drivers/gpio/Makefile | 10 +- drivers/gpio/gpio-exynos4.c | 385 ---- drivers/gpio/gpio-plat-samsung.c | 205 -- drivers/gpio/gpio-s3c24xx.c | 283 --- drivers/gpio/gpio-s3c64xx.c | 289 --- drivers/gpio/gpio-s5p64x0.c | 510 ----- drivers/gpio/gpio-s5pc100.c | 354 ---- drivers/gpio/gpio-s5pv210.c | 287 --- drivers/gpio/gpio-samsung.c | 2686 +++++++++++++++++++++++++++ 13 files changed, 2687 insertions(+), 2950 deletions(-) delete mode 100644 arch/arm/plat-samsung/gpio-config.c delete mode 100644 arch/arm/plat-samsung/gpio.c delete mode 100644 drivers/gpio/gpio-exynos4.c delete mode 100644 drivers/gpio/gpio-plat-samsung.c delete mode 100644 drivers/gpio/gpio-s3c24xx.c delete mode 100644 drivers/gpio/gpio-s3c64xx.c delete mode 100644 drivers/gpio/gpio-s5p64x0.c delete mode 100644 drivers/gpio/gpio-s5pc100.c delete mode 100644 drivers/gpio/gpio-s5pv210.c create mode 100644 drivers/gpio/gpio-samsung.c diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 853764ba8cc5..6d772d7c012b 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -15,8 +15,6 @@ obj-y += init.o obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) += time.o obj-y += clock.o obj-y += pwm-clock.o -obj-y += gpio.o -obj-y += gpio-config.o obj-y += dev-asocdma.o obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o diff --git a/arch/arm/plat-samsung/gpio-config.c b/arch/arm/plat-samsung/gpio-config.c deleted file mode 100644 index 1c0b0401594b..000000000000 --- a/arch/arm/plat-samsung/gpio-config.c +++ /dev/null @@ -1,431 +0,0 @@ -/* linux/arch/arm/plat-s3c/gpio-config.c - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008-2010 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * S3C series GPIO configuration core - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include -#include -#include -#include - -#include -#include -#include - -int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) -{ - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); - unsigned long flags; - int offset; - int ret; - - if (!chip) - return -EINVAL; - - offset = pin - chip->chip.base; - - s3c_gpio_lock(chip, flags); - ret = s3c_gpio_do_setcfg(chip, offset, config); - s3c_gpio_unlock(chip, flags); - - return ret; -} -EXPORT_SYMBOL(s3c_gpio_cfgpin); - -int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, - unsigned int cfg) -{ - int ret; - - for (; nr > 0; nr--, start++) { - ret = s3c_gpio_cfgpin(start, cfg); - if (ret != 0) - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range); - -int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, - unsigned int cfg, s3c_gpio_pull_t pull) -{ - int ret; - - for (; nr > 0; nr--, start++) { - s3c_gpio_setpull(start, pull); - ret = s3c_gpio_cfgpin(start, cfg); - if (ret != 0) - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range); - -unsigned s3c_gpio_getcfg(unsigned int pin) -{ - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); - unsigned long flags; - unsigned ret = 0; - int offset; - - if (chip) { - offset = pin - chip->chip.base; - - s3c_gpio_lock(chip, flags); - ret = s3c_gpio_do_getcfg(chip, offset); - s3c_gpio_unlock(chip, flags); - } - - return ret; -} -EXPORT_SYMBOL(s3c_gpio_getcfg); - - -int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull) -{ - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); - unsigned long flags; - int offset, ret; - - if (!chip) - return -EINVAL; - - offset = pin - chip->chip.base; - - s3c_gpio_lock(chip, flags); - ret = s3c_gpio_do_setpull(chip, offset, pull); - s3c_gpio_unlock(chip, flags); - - return ret; -} -EXPORT_SYMBOL(s3c_gpio_setpull); - -s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin) -{ - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); - unsigned long flags; - int offset; - u32 pup = 0; - - if (chip) { - offset = pin - chip->chip.base; - - s3c_gpio_lock(chip, flags); - pup = s3c_gpio_do_getpull(chip, offset); - s3c_gpio_unlock(chip, flags); - } - - return (__force s3c_gpio_pull_t)pup; -} -EXPORT_SYMBOL(s3c_gpio_getpull); - -#ifdef CONFIG_S3C_GPIO_CFG_S3C24XX -int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip, - unsigned int off, unsigned int cfg) -{ - void __iomem *reg = chip->base; - unsigned int shift = off; - u32 con; - - if (s3c_gpio_is_cfg_special(cfg)) { - cfg &= 0xf; - - /* Map output to 0, and SFN2 to 1 */ - cfg -= 1; - if (cfg > 1) - return -EINVAL; - - cfg <<= shift; - } - - con = __raw_readl(reg); - con &= ~(0x1 << shift); - con |= cfg; - __raw_writel(con, reg); - - return 0; -} - -unsigned s3c_gpio_getcfg_s3c24xx_a(struct s3c_gpio_chip *chip, - unsigned int off) -{ - u32 con; - - con = __raw_readl(chip->base); - con >>= off; - con &= 1; - con++; - - return S3C_GPIO_SFN(con); -} - -int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip, - unsigned int off, unsigned int cfg) -{ - void __iomem *reg = chip->base; - unsigned int shift = off * 2; - u32 con; - - if (s3c_gpio_is_cfg_special(cfg)) { - cfg &= 0xf; - if (cfg > 3) - return -EINVAL; - - cfg <<= shift; - } - - con = __raw_readl(reg); - con &= ~(0x3 << shift); - con |= cfg; - __raw_writel(con, reg); - - return 0; -} - -unsigned int s3c_gpio_getcfg_s3c24xx(struct s3c_gpio_chip *chip, - unsigned int off) -{ - u32 con; - - con = __raw_readl(chip->base); - con >>= off * 2; - con &= 3; - - /* this conversion works for IN and OUT as well as special mode */ - return S3C_GPIO_SPECIAL(con); -} -#endif - -#ifdef CONFIG_S3C_GPIO_CFG_S3C64XX -int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip, - unsigned int off, unsigned int cfg) -{ - void __iomem *reg = chip->base; - unsigned int shift = (off & 7) * 4; - u32 con; - - if (off < 8 && chip->chip.ngpio > 8) - reg -= 4; - - if (s3c_gpio_is_cfg_special(cfg)) { - cfg &= 0xf; - cfg <<= shift; - } - - con = __raw_readl(reg); - con &= ~(0xf << shift); - con |= cfg; - __raw_writel(con, reg); - - return 0; -} - -unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip, - unsigned int off) -{ - void __iomem *reg = chip->base; - unsigned int shift = (off & 7) * 4; - u32 con; - - if (off < 8 && chip->chip.ngpio > 8) - reg -= 4; - - con = __raw_readl(reg); - con >>= shift; - con &= 0xf; - - /* this conversion works for IN and OUT as well as special mode */ - return S3C_GPIO_SPECIAL(con); -} - -#endif /* CONFIG_S3C_GPIO_CFG_S3C64XX */ - -#ifdef CONFIG_S3C_GPIO_PULL_UPDOWN -int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull) -{ - void __iomem *reg = chip->base + 0x08; - int shift = off * 2; - u32 pup; - - pup = __raw_readl(reg); - pup &= ~(3 << shift); - pup |= pull << shift; - __raw_writel(pup, reg); - - return 0; -} - -s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip, - unsigned int off) -{ - void __iomem *reg = chip->base + 0x08; - int shift = off * 2; - u32 pup = __raw_readl(reg); - - pup >>= shift; - pup &= 0x3; - return (__force s3c_gpio_pull_t)pup; -} - -#ifdef CONFIG_S3C_GPIO_PULL_S3C2443 -int s3c_gpio_setpull_s3c2443(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull) -{ - switch (pull) { - case S3C_GPIO_PULL_NONE: - pull = 0x01; - break; - case S3C_GPIO_PULL_UP: - pull = 0x00; - break; - case S3C_GPIO_PULL_DOWN: - pull = 0x02; - break; - } - return s3c_gpio_setpull_updown(chip, off, pull); -} - -s3c_gpio_pull_t s3c_gpio_getpull_s3c2443(struct s3c_gpio_chip *chip, - unsigned int off) -{ - s3c_gpio_pull_t pull; - - pull = s3c_gpio_getpull_updown(chip, off); - - switch (pull) { - case 0x00: - pull = S3C_GPIO_PULL_UP; - break; - case 0x01: - case 0x03: - pull = S3C_GPIO_PULL_NONE; - break; - case 0x02: - pull = S3C_GPIO_PULL_DOWN; - break; - } - - return pull; -} -#endif -#endif - -#if defined(CONFIG_S3C_GPIO_PULL_UP) || defined(CONFIG_S3C_GPIO_PULL_DOWN) -static int s3c_gpio_setpull_1(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull, - s3c_gpio_pull_t updown) -{ - void __iomem *reg = chip->base + 0x08; - u32 pup = __raw_readl(reg); - - if (pull == updown) - pup &= ~(1 << off); - else if (pull == S3C_GPIO_PULL_NONE) - pup |= (1 << off); - else - return -EINVAL; - - __raw_writel(pup, reg); - return 0; -} - -static s3c_gpio_pull_t s3c_gpio_getpull_1(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t updown) -{ - void __iomem *reg = chip->base + 0x08; - u32 pup = __raw_readl(reg); - - pup &= (1 << off); - return pup ? S3C_GPIO_PULL_NONE : updown; -} -#endif /* CONFIG_S3C_GPIO_PULL_UP || CONFIG_S3C_GPIO_PULL_DOWN */ - -#ifdef CONFIG_S3C_GPIO_PULL_UP -s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip, - unsigned int off) -{ - return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_UP); -} - -int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull) -{ - return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_UP); -} -#endif /* CONFIG_S3C_GPIO_PULL_UP */ - -#ifdef CONFIG_S3C_GPIO_PULL_DOWN -s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip, - unsigned int off) -{ - return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_DOWN); -} - -int s3c_gpio_setpull_1down(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull) -{ - return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); -} -#endif /* CONFIG_S3C_GPIO_PULL_DOWN */ - -#ifdef CONFIG_S5P_GPIO_DRVSTR -s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin) -{ - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); - unsigned int off; - void __iomem *reg; - int shift; - u32 drvstr; - - if (!chip) - return -EINVAL; - - off = pin - chip->chip.base; - shift = off * 2; - reg = chip->base + 0x0C; - - drvstr = __raw_readl(reg); - drvstr = drvstr >> shift; - drvstr &= 0x3; - - return (__force s5p_gpio_drvstr_t)drvstr; -} -EXPORT_SYMBOL(s5p_gpio_get_drvstr); - -int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr) -{ - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); - unsigned int off; - void __iomem *reg; - int shift; - u32 tmp; - - if (!chip) - return -EINVAL; - - off = pin - chip->chip.base; - shift = off * 2; - reg = chip->base + 0x0C; - - tmp = __raw_readl(reg); - tmp &= ~(0x3 << shift); - tmp |= drvstr << shift; - - __raw_writel(tmp, reg); - - return 0; -} -EXPORT_SYMBOL(s5p_gpio_set_drvstr); -#endif /* CONFIG_S5P_GPIO_DRVSTR */ diff --git a/arch/arm/plat-samsung/gpio.c b/arch/arm/plat-samsung/gpio.c deleted file mode 100644 index 7743c4b8b2fb..000000000000 --- a/arch/arm/plat-samsung/gpio.c +++ /dev/null @@ -1,167 +0,0 @@ -/* linux/arch/arm/plat-s3c/gpio.c - * - * Copyright 2008 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * S3C series GPIO core - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_S3C_GPIO_TRACK -struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END]; - -static __init void s3c_gpiolib_track(struct s3c_gpio_chip *chip) -{ - unsigned int gpn; - int i; - - gpn = chip->chip.base; - for (i = 0; i < chip->chip.ngpio; i++, gpn++) { - BUG_ON(gpn >= ARRAY_SIZE(s3c_gpios)); - s3c_gpios[gpn] = chip; - } -} -#endif /* CONFIG_S3C_GPIO_TRACK */ - -/* Default routines for controlling GPIO, based on the original S3C24XX - * GPIO functions which deal with the case where each gpio bank of the - * chip is as following: - * - * base + 0x00: Control register, 2 bits per gpio - * gpio n: 2 bits starting at (2*n) - * 00 = input, 01 = output, others mean special-function - * base + 0x04: Data register, 1 bit per gpio - * bit n: data bit n -*/ - -static int s3c_gpiolib_input(struct gpio_chip *chip, unsigned offset) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - unsigned long flags; - unsigned long con; - - s3c_gpio_lock(ourchip, flags); - - con = __raw_readl(base + 0x00); - con &= ~(3 << (offset * 2)); - - __raw_writel(con, base + 0x00); - - s3c_gpio_unlock(ourchip, flags); - return 0; -} - -static int s3c_gpiolib_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - unsigned long flags; - unsigned long dat; - unsigned long con; - - s3c_gpio_lock(ourchip, flags); - - dat = __raw_readl(base + 0x04); - dat &= ~(1 << offset); - if (value) - dat |= 1 << offset; - __raw_writel(dat, base + 0x04); - - con = __raw_readl(base + 0x00); - con &= ~(3 << (offset * 2)); - con |= 1 << (offset * 2); - - __raw_writel(con, base + 0x00); - __raw_writel(dat, base + 0x04); - - s3c_gpio_unlock(ourchip, flags); - return 0; -} - -static void s3c_gpiolib_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - unsigned long flags; - unsigned long dat; - - s3c_gpio_lock(ourchip, flags); - - dat = __raw_readl(base + 0x04); - dat &= ~(1 << offset); - if (value) - dat |= 1 << offset; - __raw_writel(dat, base + 0x04); - - s3c_gpio_unlock(ourchip, flags); -} - -static int s3c_gpiolib_get(struct gpio_chip *chip, unsigned offset) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - unsigned long val; - - val = __raw_readl(ourchip->base + 0x04); - val >>= offset; - val &= 1; - - return val; -} - -__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip) -{ - struct gpio_chip *gc = &chip->chip; - int ret; - - BUG_ON(!chip->base); - BUG_ON(!gc->label); - BUG_ON(!gc->ngpio); - - spin_lock_init(&chip->lock); - - if (!gc->direction_input) - gc->direction_input = s3c_gpiolib_input; - if (!gc->direction_output) - gc->direction_output = s3c_gpiolib_output; - if (!gc->set) - gc->set = s3c_gpiolib_set; - if (!gc->get) - gc->get = s3c_gpiolib_get; - -#ifdef CONFIG_PM - if (chip->pm != NULL) { - if (!chip->pm->save || !chip->pm->resume) - printk(KERN_ERR "gpio: %s has missing PM functions\n", - gc->label); - } else - printk(KERN_ERR "gpio: %s has no PM function\n", gc->label); -#endif - - /* gpiochip_add() prints own failure message on error. */ - ret = gpiochip_add(gc); - if (ret >= 0) - s3c_gpiolib_track(chip); -} - -int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - struct s3c_gpio_chip *s3c_chip = container_of(chip, - struct s3c_gpio_chip, chip); - - return s3c_chip->irq_base + offset; -} diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5eb29bc18a56..ca44d2cceb02 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -95,10 +95,6 @@ config GPIO_EP93XX depends on ARCH_EP93XX select GPIO_GENERIC -config GPIO_EXYNOS4 - def_bool y - depends on CPU_EXYNOS4210 - config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx @@ -131,30 +127,6 @@ config GPIO_MXS select GPIO_GENERIC select GENERIC_IRQ_CHIP -config GPIO_PLAT_SAMSUNG - def_bool y - depends on SAMSUNG_GPIOLIB_4BIT - -config GPIO_S3C24XX - def_bool y - depends on PLAT_S3C24XX - -config GPIO_S3C64XX - def_bool y - depends on ARCH_S3C64XX - -config GPIO_S5P64X0 - def_bool y - depends on ARCH_S5P64X0 - -config GPIO_S5PC100 - def_bool y - depends on CPU_S5PC100 - -config GPIO_S5PV210 - def_bool y - depends on CPU_S5PV210 - config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 10f3bbf0eceb..62db458c850d 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o -obj-$(CONFIG_GPIO_EXYNOS4) += gpio-exynos4.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o @@ -38,14 +37,7 @@ obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o - -obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o -obj-$(CONFIG_GPIO_S3C24XX) += gpio-s3c24xx.o -obj-$(CONFIG_GPIO_S3C64XX) += gpio-s3c64xx.o -obj-$(CONFIG_GPIO_S5P64X0) += gpio-s5p64x0.o -obj-$(CONFIG_GPIO_S5PC100) += gpio-s5pc100.o -obj-$(CONFIG_GPIO_S5PV210) += gpio-s5pv210.o - +obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o diff --git a/drivers/gpio/gpio-exynos4.c b/drivers/gpio/gpio-exynos4.c deleted file mode 100644 index d24b337cf1ac..000000000000 --- a/drivers/gpio/gpio-exynos4.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * EXYNOS4 - GPIOlib support - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include -#include -#include -#include - -#include - -#include -#include -#include - -int s3c_gpio_setpull_exynos4(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull) -{ - if (pull == S3C_GPIO_PULL_UP) - pull = 3; - - return s3c_gpio_setpull_updown(chip, off, pull); -} - -s3c_gpio_pull_t s3c_gpio_getpull_exynos4(struct s3c_gpio_chip *chip, - unsigned int off) -{ - s3c_gpio_pull_t pull; - - pull = s3c_gpio_getpull_updown(chip, off); - if (pull == 3) - pull = S3C_GPIO_PULL_UP; - - return pull; -} - -static struct s3c_gpio_cfg gpio_cfg = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_exynos4, - .get_pull = s3c_gpio_getpull_exynos4, -}; - -static struct s3c_gpio_cfg gpio_cfg_noint = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_exynos4, - .get_pull = s3c_gpio_getpull_exynos4, -}; - -/* - * Following are the gpio banks in v310. - * - * The 'config' member when left to NULL, is initialized to the default - * structure gpio_cfg in the init function below. - * - * The 'base' member is also initialized in the init function below. - * Note: The initialization of 'base' member of s3c_gpio_chip structure - * uses the above macro and depends on the banks being listed in order here. - */ -static struct s3c_gpio_chip exynos4_gpio_part1_4bit[] = { - { - .chip = { - .base = EXYNOS4_GPA0(0), - .ngpio = EXYNOS4_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = EXYNOS4_GPA1(0), - .ngpio = EXYNOS4_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = EXYNOS4_GPB(0), - .ngpio = EXYNOS4_GPIO_B_NR, - .label = "GPB", - }, - }, { - .chip = { - .base = EXYNOS4_GPC0(0), - .ngpio = EXYNOS4_GPIO_C0_NR, - .label = "GPC0", - }, - }, { - .chip = { - .base = EXYNOS4_GPC1(0), - .ngpio = EXYNOS4_GPIO_C1_NR, - .label = "GPC1", - }, - }, { - .chip = { - .base = EXYNOS4_GPD0(0), - .ngpio = EXYNOS4_GPIO_D0_NR, - .label = "GPD0", - }, - }, { - .chip = { - .base = EXYNOS4_GPD1(0), - .ngpio = EXYNOS4_GPIO_D1_NR, - .label = "GPD1", - }, - }, { - .chip = { - .base = EXYNOS4_GPE0(0), - .ngpio = EXYNOS4_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = EXYNOS4_GPE1(0), - .ngpio = EXYNOS4_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = EXYNOS4_GPE2(0), - .ngpio = EXYNOS4_GPIO_E2_NR, - .label = "GPE2", - }, - }, { - .chip = { - .base = EXYNOS4_GPE3(0), - .ngpio = EXYNOS4_GPIO_E3_NR, - .label = "GPE3", - }, - }, { - .chip = { - .base = EXYNOS4_GPE4(0), - .ngpio = EXYNOS4_GPIO_E4_NR, - .label = "GPE4", - }, - }, { - .chip = { - .base = EXYNOS4_GPF0(0), - .ngpio = EXYNOS4_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = EXYNOS4_GPF1(0), - .ngpio = EXYNOS4_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = EXYNOS4_GPF2(0), - .ngpio = EXYNOS4_GPIO_F2_NR, - .label = "GPF2", - }, - }, { - .chip = { - .base = EXYNOS4_GPF3(0), - .ngpio = EXYNOS4_GPIO_F3_NR, - .label = "GPF3", - }, - }, -}; - -static struct s3c_gpio_chip exynos4_gpio_part2_4bit[] = { - { - .chip = { - .base = EXYNOS4_GPJ0(0), - .ngpio = EXYNOS4_GPIO_J0_NR, - .label = "GPJ0", - }, - }, { - .chip = { - .base = EXYNOS4_GPJ1(0), - .ngpio = EXYNOS4_GPIO_J1_NR, - .label = "GPJ1", - }, - }, { - .chip = { - .base = EXYNOS4_GPK0(0), - .ngpio = EXYNOS4_GPIO_K0_NR, - .label = "GPK0", - }, - }, { - .chip = { - .base = EXYNOS4_GPK1(0), - .ngpio = EXYNOS4_GPIO_K1_NR, - .label = "GPK1", - }, - }, { - .chip = { - .base = EXYNOS4_GPK2(0), - .ngpio = EXYNOS4_GPIO_K2_NR, - .label = "GPK2", - }, - }, { - .chip = { - .base = EXYNOS4_GPK3(0), - .ngpio = EXYNOS4_GPIO_K3_NR, - .label = "GPK3", - }, - }, { - .chip = { - .base = EXYNOS4_GPL0(0), - .ngpio = EXYNOS4_GPIO_L0_NR, - .label = "GPL0", - }, - }, { - .chip = { - .base = EXYNOS4_GPL1(0), - .ngpio = EXYNOS4_GPIO_L1_NR, - .label = "GPL1", - }, - }, { - .chip = { - .base = EXYNOS4_GPL2(0), - .ngpio = EXYNOS4_GPIO_L2_NR, - .label = "GPL2", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY0(0), - .ngpio = EXYNOS4_GPIO_Y0_NR, - .label = "GPY0", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY1(0), - .ngpio = EXYNOS4_GPIO_Y1_NR, - .label = "GPY1", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY2(0), - .ngpio = EXYNOS4_GPIO_Y2_NR, - .label = "GPY2", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY3(0), - .ngpio = EXYNOS4_GPIO_Y3_NR, - .label = "GPY3", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY4(0), - .ngpio = EXYNOS4_GPIO_Y4_NR, - .label = "GPY4", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY5(0), - .ngpio = EXYNOS4_GPIO_Y5_NR, - .label = "GPY5", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = EXYNOS4_GPY6(0), - .ngpio = EXYNOS4_GPIO_Y6_NR, - .label = "GPY6", - }, - }, { - .base = (S5P_VA_GPIO2 + 0xC00), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(0), - .chip = { - .base = EXYNOS4_GPX0(0), - .ngpio = EXYNOS4_GPIO_X0_NR, - .label = "GPX0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO2 + 0xC20), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(8), - .chip = { - .base = EXYNOS4_GPX1(0), - .ngpio = EXYNOS4_GPIO_X1_NR, - .label = "GPX1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO2 + 0xC40), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(16), - .chip = { - .base = EXYNOS4_GPX2(0), - .ngpio = EXYNOS4_GPIO_X2_NR, - .label = "GPX2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO2 + 0xC60), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(24), - .chip = { - .base = EXYNOS4_GPX3(0), - .ngpio = EXYNOS4_GPIO_X3_NR, - .label = "GPX3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; - -static struct s3c_gpio_chip exynos4_gpio_part3_4bit[] = { - { - .chip = { - .base = EXYNOS4_GPZ(0), - .ngpio = EXYNOS4_GPIO_Z_NR, - .label = "GPZ", - }, - }, -}; - -static __init int exynos4_gpiolib_init(void) -{ - struct s3c_gpio_chip *chip; - int i; - int group = 0; - int nr_chips; - - /* GPIO part 1 */ - - chip = exynos4_gpio_part1_4bit; - nr_chips = ARRAY_SIZE(exynos4_gpio_part1_4bit); - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - /* Assign the GPIO interrupt group */ - chip->group = group++; - } - if (chip->base == NULL) - chip->base = S5P_VA_GPIO1 + (i) * 0x20; - } - - samsung_gpiolib_add_4bit_chips(exynos4_gpio_part1_4bit, nr_chips); - - /* GPIO part 2 */ - - chip = exynos4_gpio_part2_4bit; - nr_chips = ARRAY_SIZE(exynos4_gpio_part2_4bit); - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - /* Assign the GPIO interrupt group */ - chip->group = group++; - } - if (chip->base == NULL) - chip->base = S5P_VA_GPIO2 + (i) * 0x20; - } - - samsung_gpiolib_add_4bit_chips(exynos4_gpio_part2_4bit, nr_chips); - - /* GPIO part 3 */ - - chip = exynos4_gpio_part3_4bit; - nr_chips = ARRAY_SIZE(exynos4_gpio_part3_4bit); - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - /* Assign the GPIO interrupt group */ - chip->group = group++; - } - if (chip->base == NULL) - chip->base = S5P_VA_GPIO3 + (i) * 0x20; - } - - samsung_gpiolib_add_4bit_chips(exynos4_gpio_part3_4bit, nr_chips); - s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); - s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); - - return 0; -} -core_initcall(exynos4_gpiolib_init); diff --git a/drivers/gpio/gpio-plat-samsung.c b/drivers/gpio/gpio-plat-samsung.c deleted file mode 100644 index ef67f1952a72..000000000000 --- a/drivers/gpio/gpio-plat-samsung.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * Copyright (c) 2009 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * SAMSUNG - GPIOlib support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifndef DEBUG_GPIO -#define gpio_dbg(x...) do { } while (0) -#else -#define gpio_dbg(x...) printk(KERN_DEBUG x) -#endif - -/* The samsung_gpiolib_4bit routines are to control the gpio banks where - * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the - * following example: - * - * base + 0x00: Control register, 4 bits per gpio - * gpio n: 4 bits starting at (4*n) - * 0000 = input, 0001 = output, others mean special-function - * base + 0x04: Data register, 1 bit per gpio - * bit n: data bit n - * - * Note, since the data register is one bit per gpio and is at base + 0x4 - * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of - * the output. -*/ - -static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - unsigned long con; - - con = __raw_readl(base + GPIOCON_OFF); - con &= ~(0xf << con_4bit_shift(offset)); - __raw_writel(con, base + GPIOCON_OFF); - - gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); - - return 0; -} - -static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - unsigned long con; - unsigned long dat; - - con = __raw_readl(base + GPIOCON_OFF); - con &= ~(0xf << con_4bit_shift(offset)); - con |= 0x1 << con_4bit_shift(offset); - - dat = __raw_readl(base + GPIODAT_OFF); - - if (value) - dat |= 1 << offset; - else - dat &= ~(1 << offset); - - __raw_writel(dat, base + GPIODAT_OFF); - __raw_writel(con, base + GPIOCON_OFF); - __raw_writel(dat, base + GPIODAT_OFF); - - gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); - - return 0; -} - -/* The next set of routines are for the case where the GPIO configuration - * registers are 4 bits per GPIO but there is more than one register (the - * bank has more than 8 GPIOs. - * - * This case is the similar to the 4 bit case, but the registers are as - * follows: - * - * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs) - * gpio n: 4 bits starting at (4*n) - * 0000 = input, 0001 = output, others mean special-function - * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs) - * gpio n: 4 bits starting at (4*n) - * 0000 = input, 0001 = output, others mean special-function - * base + 0x08: Data register, 1 bit per gpio - * bit n: data bit n - * - * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we - * store the 'base + 0x4' address so that these routines see the data - * register at ourchip->base + 0x04. - */ - -static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - void __iomem *regcon = base; - unsigned long con; - - if (offset > 7) - offset -= 8; - else - regcon -= 4; - - con = __raw_readl(regcon); - con &= ~(0xf << con_4bit_shift(offset)); - __raw_writel(con, regcon); - - gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con); - - return 0; -} - -static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - void __iomem *regcon = base; - unsigned long con; - unsigned long dat; - unsigned con_offset = offset; - - if (con_offset > 7) - con_offset -= 8; - else - regcon -= 4; - - con = __raw_readl(regcon); - con &= ~(0xf << con_4bit_shift(con_offset)); - con |= 0x1 << con_4bit_shift(con_offset); - - dat = __raw_readl(base + GPIODAT_OFF); - - if (value) - dat |= 1 << offset; - else - dat &= ~(1 << offset); - - __raw_writel(dat, base + GPIODAT_OFF); - __raw_writel(con, regcon); - __raw_writel(dat, base + GPIODAT_OFF); - - gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); - - return 0; -} - -void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip) -{ - chip->chip.direction_input = samsung_gpiolib_4bit_input; - chip->chip.direction_output = samsung_gpiolib_4bit_output; - chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); -} - -void __init samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip) -{ - chip->chip.direction_input = samsung_gpiolib_4bit2_input; - chip->chip.direction_output = samsung_gpiolib_4bit2_output; - chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); -} - -void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip, - int nr_chips) -{ - for (; nr_chips > 0; nr_chips--, chip++) { - samsung_gpiolib_add_4bit(chip); - s3c_gpiolib_add(chip); - } -} - -void __init samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip, - int nr_chips) -{ - for (; nr_chips > 0; nr_chips--, chip++) { - samsung_gpiolib_add_4bit2(chip); - s3c_gpiolib_add(chip); - } -} - -void __init samsung_gpiolib_add_2bit_chips(struct s3c_gpio_chip *chip, - int nr_chips) -{ - for (; nr_chips > 0; nr_chips--, chip++) - s3c_gpiolib_add(chip); -} diff --git a/drivers/gpio/gpio-s3c24xx.c b/drivers/gpio/gpio-s3c24xx.c deleted file mode 100644 index ff6103130fe8..000000000000 --- a/drivers/gpio/gpio-s3c24xx.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 2008-2010 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C24XX GPIOlib support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset) -{ - return -EINVAL; -} - -static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - unsigned long flags; - unsigned long dat; - unsigned long con; - - local_irq_save(flags); - - con = __raw_readl(base + 0x00); - dat = __raw_readl(base + 0x04); - - dat &= ~(1 << offset); - if (value) - dat |= 1 << offset; - - __raw_writel(dat, base + 0x04); - - con &= ~(1 << offset); - - __raw_writel(con, base + 0x00); - __raw_writel(dat, base + 0x04); - - local_irq_restore(flags); - return 0; -} - -static int s3c24xx_gpiolib_bankf_toirq(struct gpio_chip *chip, unsigned offset) -{ - if (offset < 4) - return IRQ_EINT0 + offset; - - if (offset < 8) - return IRQ_EINT4 + offset - 4; - - return -EINVAL; -} - -static struct s3c_gpio_cfg s3c24xx_gpiocfg_banka = { - .set_config = s3c_gpio_setcfg_s3c24xx_a, - .get_config = s3c_gpio_getcfg_s3c24xx_a, -}; - -struct s3c_gpio_cfg s3c24xx_gpiocfg_default = { - .set_config = s3c_gpio_setcfg_s3c24xx, - .get_config = s3c_gpio_getcfg_s3c24xx, -}; - -struct s3c_gpio_chip s3c24xx_gpios[] = { - [0] = { - .base = S3C2410_GPACON, - .pm = __gpio_pm(&s3c_gpio_pm_1bit), - .config = &s3c24xx_gpiocfg_banka, - .chip = { - .base = S3C2410_GPA(0), - .owner = THIS_MODULE, - .label = "GPIOA", - .ngpio = 24, - .direction_input = s3c24xx_gpiolib_banka_input, - .direction_output = s3c24xx_gpiolib_banka_output, - }, - }, - [1] = { - .base = S3C2410_GPBCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPB(0), - .owner = THIS_MODULE, - .label = "GPIOB", - .ngpio = 16, - }, - }, - [2] = { - .base = S3C2410_GPCCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPC(0), - .owner = THIS_MODULE, - .label = "GPIOC", - .ngpio = 16, - }, - }, - [3] = { - .base = S3C2410_GPDCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPD(0), - .owner = THIS_MODULE, - .label = "GPIOD", - .ngpio = 16, - }, - }, - [4] = { - .base = S3C2410_GPECON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPE(0), - .label = "GPIOE", - .owner = THIS_MODULE, - .ngpio = 16, - }, - }, - [5] = { - .base = S3C2410_GPFCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPF(0), - .owner = THIS_MODULE, - .label = "GPIOF", - .ngpio = 8, - .to_irq = s3c24xx_gpiolib_bankf_toirq, - }, - }, - [6] = { - .base = S3C2410_GPGCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .irq_base = IRQ_EINT8, - .chip = { - .base = S3C2410_GPG(0), - .owner = THIS_MODULE, - .label = "GPIOG", - .ngpio = 16, - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = S3C2410_GPHCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPH(0), - .owner = THIS_MODULE, - .label = "GPIOH", - .ngpio = 11, - }, - }, - /* GPIOS for the S3C2443 and later devices. */ - { - .base = S3C2440_GPJCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPJ(0), - .owner = THIS_MODULE, - .label = "GPIOJ", - .ngpio = 16, - }, - }, { - .base = S3C2443_GPKCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPK(0), - .owner = THIS_MODULE, - .label = "GPIOK", - .ngpio = 16, - }, - }, { - .base = S3C2443_GPLCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPL(0), - .owner = THIS_MODULE, - .label = "GPIOL", - .ngpio = 15, - }, - }, { - .base = S3C2443_GPMCON, - .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPM(0), - .owner = THIS_MODULE, - .label = "GPIOM", - .ngpio = 2, - }, - }, -}; - -static __init int s3c24xx_gpiolib_init(void) -{ - struct s3c_gpio_chip *chip = s3c24xx_gpios; - int gpn; - - for (gpn = 0; gpn < ARRAY_SIZE(s3c24xx_gpios); gpn++, chip++) { - if (!chip->config) - chip->config = &s3c24xx_gpiocfg_default; - - s3c_gpiolib_add(chip); - } - - return 0; -} -core_initcall(s3c24xx_gpiolib_init); - -/* gpiolib wrappers until these are totally eliminated */ - -void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) -{ - int ret; - - WARN_ON(to); /* should be none of these left */ - - if (!to) { - /* if pull is enabled, try first with up, and if that - * fails, try using down */ - - ret = s3c_gpio_setpull(pin, S3C_GPIO_PULL_UP); - if (ret) - s3c_gpio_setpull(pin, S3C_GPIO_PULL_DOWN); - } else { - s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE); - } -} -EXPORT_SYMBOL(s3c2410_gpio_pullup); - -void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) -{ - /* do this via gpiolib until all users removed */ - - gpio_request(pin, "temporary"); - gpio_set_value(pin, to); - gpio_free(pin); -} -EXPORT_SYMBOL(s3c2410_gpio_setpin); - -unsigned int s3c2410_gpio_getpin(unsigned int pin) -{ - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); - unsigned long offs = pin - chip->chip.base; - - return __raw_readl(chip->base + 0x04) & (1<< offs); -} -EXPORT_SYMBOL(s3c2410_gpio_getpin); - -unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) -{ - unsigned long flags; - unsigned long misccr; - - local_irq_save(flags); - misccr = __raw_readl(S3C24XX_MISCCR); - misccr &= ~clear; - misccr ^= change; - __raw_writel(misccr, S3C24XX_MISCCR); - local_irq_restore(flags); - - return misccr; -} -EXPORT_SYMBOL(s3c2410_modify_misccr); diff --git a/drivers/gpio/gpio-s3c64xx.c b/drivers/gpio/gpio-s3c64xx.c deleted file mode 100644 index b4f1c8204f03..000000000000 --- a/drivers/gpio/gpio-s3c64xx.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * S3C64XX - GPIOlib support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -/* GPIO bank summary: - * - * Bank GPIOs Style SlpCon ExtInt Group - * A 8 4Bit Yes 1 - * B 7 4Bit Yes 1 - * C 8 4Bit Yes 2 - * D 5 4Bit Yes 3 - * E 5 4Bit Yes None - * F 16 2Bit Yes 4 [1] - * G 7 4Bit Yes 5 - * H 10 4Bit[2] Yes 6 - * I 16 2Bit Yes None - * J 12 2Bit Yes None - * K 16 4Bit[2] No None - * L 15 4Bit[2] No None - * M 6 4Bit No IRQ_EINT - * N 16 2Bit No IRQ_EINT - * O 16 2Bit Yes 7 - * P 15 2Bit Yes 8 - * Q 9 2Bit Yes 9 - * - * [1] BANKF pins 14,15 do not form part of the external interrupt sources - * [2] BANK has two control registers, GPxCON0 and GPxCON1 - */ - -static struct s3c_gpio_cfg gpio_4bit_cfg_noint = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .get_config = s3c_gpio_getcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_4bit_cfg_eint0111 = { - .cfg_eint = 7, - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .get_config = s3c_gpio_getcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = { - .cfg_eint = 3, - .get_config = s3c_gpio_getcfg_s3c64xx_4bit, - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static int s3c64xx_gpio2int_gpm(struct gpio_chip *chip, unsigned pin) -{ - return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO; -} - -static struct s3c_gpio_chip gpio_4bit[] = { - { - .base = S3C64XX_GPA_BASE, - .config = &gpio_4bit_cfg_eint0111, - .chip = { - .base = S3C64XX_GPA(0), - .ngpio = S3C64XX_GPIO_A_NR, - .label = "GPA", - }, - }, { - .base = S3C64XX_GPB_BASE, - .config = &gpio_4bit_cfg_eint0111, - .chip = { - .base = S3C64XX_GPB(0), - .ngpio = S3C64XX_GPIO_B_NR, - .label = "GPB", - }, - }, { - .base = S3C64XX_GPC_BASE, - .config = &gpio_4bit_cfg_eint0111, - .chip = { - .base = S3C64XX_GPC(0), - .ngpio = S3C64XX_GPIO_C_NR, - .label = "GPC", - }, - }, { - .base = S3C64XX_GPD_BASE, - .config = &gpio_4bit_cfg_eint0111, - .chip = { - .base = S3C64XX_GPD(0), - .ngpio = S3C64XX_GPIO_D_NR, - .label = "GPD", - }, - }, { - .base = S3C64XX_GPE_BASE, - .config = &gpio_4bit_cfg_noint, - .chip = { - .base = S3C64XX_GPE(0), - .ngpio = S3C64XX_GPIO_E_NR, - .label = "GPE", - }, - }, { - .base = S3C64XX_GPG_BASE, - .config = &gpio_4bit_cfg_eint0111, - .chip = { - .base = S3C64XX_GPG(0), - .ngpio = S3C64XX_GPIO_G_NR, - .label = "GPG", - }, - }, { - .base = S3C64XX_GPM_BASE, - .config = &gpio_4bit_cfg_eint0011, - .chip = { - .base = S3C64XX_GPM(0), - .ngpio = S3C64XX_GPIO_M_NR, - .label = "GPM", - .to_irq = s3c64xx_gpio2int_gpm, - }, - }, -}; - -static int s3c64xx_gpio2int_gpl(struct gpio_chip *chip, unsigned pin) -{ - return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO; -} - -static struct s3c_gpio_chip gpio_4bit2[] = { - { - .base = S3C64XX_GPH_BASE + 0x4, - .config = &gpio_4bit_cfg_eint0111, - .chip = { - .base = S3C64XX_GPH(0), - .ngpio = S3C64XX_GPIO_H_NR, - .label = "GPH", - }, - }, { - .base = S3C64XX_GPK_BASE + 0x4, - .config = &gpio_4bit_cfg_noint, - .chip = { - .base = S3C64XX_GPK(0), - .ngpio = S3C64XX_GPIO_K_NR, - .label = "GPK", - }, - }, { - .base = S3C64XX_GPL_BASE + 0x4, - .config = &gpio_4bit_cfg_eint0011, - .chip = { - .base = S3C64XX_GPL(0), - .ngpio = S3C64XX_GPIO_L_NR, - .label = "GPL", - .to_irq = s3c64xx_gpio2int_gpl, - }, - }, -}; - -static struct s3c_gpio_cfg gpio_2bit_cfg_noint = { - .set_config = s3c_gpio_setcfg_s3c24xx, - .get_config = s3c_gpio_getcfg_s3c24xx, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_2bit_cfg_eint10 = { - .cfg_eint = 2, - .set_config = s3c_gpio_setcfg_s3c24xx, - .get_config = s3c_gpio_getcfg_s3c24xx, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_2bit_cfg_eint11 = { - .cfg_eint = 3, - .set_config = s3c_gpio_setcfg_s3c24xx, - .get_config = s3c_gpio_getcfg_s3c24xx, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_chip gpio_2bit[] = { - { - .base = S3C64XX_GPF_BASE, - .config = &gpio_2bit_cfg_eint11, - .chip = { - .base = S3C64XX_GPF(0), - .ngpio = S3C64XX_GPIO_F_NR, - .label = "GPF", - }, - }, { - .base = S3C64XX_GPI_BASE, - .config = &gpio_2bit_cfg_noint, - .chip = { - .base = S3C64XX_GPI(0), - .ngpio = S3C64XX_GPIO_I_NR, - .label = "GPI", - }, - }, { - .base = S3C64XX_GPJ_BASE, - .config = &gpio_2bit_cfg_noint, - .chip = { - .base = S3C64XX_GPJ(0), - .ngpio = S3C64XX_GPIO_J_NR, - .label = "GPJ", - }, - }, { - .base = S3C64XX_GPN_BASE, - .irq_base = IRQ_EINT(0), - .config = &gpio_2bit_cfg_eint10, - .chip = { - .base = S3C64XX_GPN(0), - .ngpio = S3C64XX_GPIO_N_NR, - .label = "GPN", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = S3C64XX_GPO_BASE, - .config = &gpio_2bit_cfg_eint11, - .chip = { - .base = S3C64XX_GPO(0), - .ngpio = S3C64XX_GPIO_O_NR, - .label = "GPO", - }, - }, { - .base = S3C64XX_GPP_BASE, - .config = &gpio_2bit_cfg_eint11, - .chip = { - .base = S3C64XX_GPP(0), - .ngpio = S3C64XX_GPIO_P_NR, - .label = "GPP", - }, - }, { - .base = S3C64XX_GPQ_BASE, - .config = &gpio_2bit_cfg_eint11, - .chip = { - .base = S3C64XX_GPQ(0), - .ngpio = S3C64XX_GPIO_Q_NR, - .label = "GPQ", - }, - }, -}; - -static __init void s3c64xx_gpiolib_add_2bit(struct s3c_gpio_chip *chip) -{ - chip->pm = __gpio_pm(&s3c_gpio_pm_2bit); -} - -static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips, - int nr_chips, - void (*fn)(struct s3c_gpio_chip *)) -{ - for (; nr_chips > 0; nr_chips--, chips++) { - if (fn) - (fn)(chips); - s3c_gpiolib_add(chips); - } -} - -static __init int s3c64xx_gpiolib_init(void) -{ - s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit), - samsung_gpiolib_add_4bit); - - s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2), - samsung_gpiolib_add_4bit2); - - s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), - s3c64xx_gpiolib_add_2bit); - - return 0; -} - -core_initcall(s3c64xx_gpiolib_init); diff --git a/drivers/gpio/gpio-s5p64x0.c b/drivers/gpio/gpio-s5p64x0.c deleted file mode 100644 index 96e816f5cc95..000000000000 --- a/drivers/gpio/gpio-s5p64x0.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * S5P64X0 - GPIOlib support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -/* - * S5P6440 GPIO bank summary: - * - * Bank GPIOs Style SlpCon ExtInt Group - * A 6 4Bit Yes 1 - * B 7 4Bit Yes 1 - * C 8 4Bit Yes 2 - * F 2 2Bit Yes 4 [1] - * G 7 4Bit Yes 5 - * H 10 4Bit[2] Yes 6 - * I 16 2Bit Yes None - * J 12 2Bit Yes None - * N 16 2Bit No IRQ_EINT - * P 8 2Bit Yes 8 - * R 15 4Bit[2] Yes 8 - * - * S5P6450 GPIO bank summary: - * - * Bank GPIOs Style SlpCon ExtInt Group - * A 6 4Bit Yes 1 - * B 7 4Bit Yes 1 - * C 8 4Bit Yes 2 - * D 8 4Bit Yes None - * F 2 2Bit Yes None - * G 14 4Bit[2] Yes 5 - * H 10 4Bit[2] Yes 6 - * I 16 2Bit Yes None - * J 12 2Bit Yes None - * K 5 4Bit Yes None - * N 16 2Bit No IRQ_EINT - * P 11 2Bit Yes 8 - * Q 14 2Bit Yes None - * R 15 4Bit[2] Yes None - * S 8 2Bit Yes None - * - * [1] BANKF pins 14,15 do not form part of the external interrupt sources - * [2] BANK has two control registers, GPxCON0 and GPxCON1 - */ - -static int s5p64x0_gpiolib_rbank_4bit2_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - void __iomem *regcon = base; - unsigned long con; - unsigned long flags; - - switch (offset) { - case 6: - offset += 1; - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - regcon -= 4; - break; - default: - offset -= 7; - break; - } - - s3c_gpio_lock(ourchip, flags); - - con = __raw_readl(regcon); - con &= ~(0xf << con_4bit_shift(offset)); - __raw_writel(con, regcon); - - s3c_gpio_unlock(ourchip, flags); - - return 0; -} - -static int s5p64x0_gpiolib_rbank_4bit2_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); - void __iomem *base = ourchip->base; - void __iomem *regcon = base; - unsigned long con; - unsigned long dat; - unsigned long flags; - unsigned con_offset = offset; - - switch (con_offset) { - case 6: - con_offset += 1; - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - regcon -= 4; - break; - default: - con_offset -= 7; - break; - } - - s3c_gpio_lock(ourchip, flags); - - con = __raw_readl(regcon); - con &= ~(0xf << con_4bit_shift(con_offset)); - con |= 0x1 << con_4bit_shift(con_offset); - - dat = __raw_readl(base + GPIODAT_OFF); - if (value) - dat |= 1 << offset; - else - dat &= ~(1 << offset); - - __raw_writel(con, regcon); - __raw_writel(dat, base + GPIODAT_OFF); - - s3c_gpio_unlock(ourchip, flags); - - return 0; -} - -int s5p64x0_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip, - unsigned int off, unsigned int cfg) -{ - void __iomem *reg = chip->base; - unsigned int shift; - u32 con; - - switch (off) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - shift = (off & 7) * 4; - reg -= 4; - break; - case 6: - shift = ((off + 1) & 7) * 4; - reg -= 4; - default: - shift = ((off + 1) & 7) * 4; - break; - } - - if (s3c_gpio_is_cfg_special(cfg)) { - cfg &= 0xf; - cfg <<= shift; - } - - con = __raw_readl(reg); - con &= ~(0xf << shift); - con |= cfg; - __raw_writel(con, reg); - - return 0; -} - -static struct s3c_gpio_cfg s5p64x0_gpio_cfgs[] = { - { - .cfg_eint = 0, - }, { - .cfg_eint = 7, - }, { - .cfg_eint = 3, - .set_config = s5p64x0_gpio_setcfg_4bit_rbank, - }, { - .cfg_eint = 0, - .set_config = s3c_gpio_setcfg_s3c24xx, - .get_config = s3c_gpio_getcfg_s3c24xx, - }, { - .cfg_eint = 2, - .set_config = s3c_gpio_setcfg_s3c24xx, - .get_config = s3c_gpio_getcfg_s3c24xx, - }, { - .cfg_eint = 3, - .set_config = s3c_gpio_setcfg_s3c24xx, - .get_config = s3c_gpio_getcfg_s3c24xx, - }, -}; - -static struct s3c_gpio_chip s5p6440_gpio_4bit[] = { - { - .base = S5P64X0_GPA_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6440_GPA(0), - .ngpio = S5P6440_GPIO_A_NR, - .label = "GPA", - }, - }, { - .base = S5P64X0_GPB_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6440_GPB(0), - .ngpio = S5P6440_GPIO_B_NR, - .label = "GPB", - }, - }, { - .base = S5P64X0_GPC_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6440_GPC(0), - .ngpio = S5P6440_GPIO_C_NR, - .label = "GPC", - }, - }, { - .base = S5P64X0_GPG_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6440_GPG(0), - .ngpio = S5P6440_GPIO_G_NR, - .label = "GPG", - }, - }, -}; - -static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = { - { - .base = S5P64X0_GPH_BASE + 0x4, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6440_GPH(0), - .ngpio = S5P6440_GPIO_H_NR, - .label = "GPH", - }, - }, -}; - -static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = { - { - .base = S5P64X0_GPR_BASE + 0x4, - .config = &s5p64x0_gpio_cfgs[2], - .chip = { - .base = S5P6440_GPR(0), - .ngpio = S5P6440_GPIO_R_NR, - .label = "GPR", - }, - }, -}; - -static struct s3c_gpio_chip s5p6440_gpio_2bit[] = { - { - .base = S5P64X0_GPF_BASE, - .config = &s5p64x0_gpio_cfgs[5], - .chip = { - .base = S5P6440_GPF(0), - .ngpio = S5P6440_GPIO_F_NR, - .label = "GPF", - }, - }, { - .base = S5P64X0_GPI_BASE, - .config = &s5p64x0_gpio_cfgs[3], - .chip = { - .base = S5P6440_GPI(0), - .ngpio = S5P6440_GPIO_I_NR, - .label = "GPI", - }, - }, { - .base = S5P64X0_GPJ_BASE, - .config = &s5p64x0_gpio_cfgs[3], - .chip = { - .base = S5P6440_GPJ(0), - .ngpio = S5P6440_GPIO_J_NR, - .label = "GPJ", - }, - }, { - .base = S5P64X0_GPN_BASE, - .config = &s5p64x0_gpio_cfgs[4], - .chip = { - .base = S5P6440_GPN(0), - .ngpio = S5P6440_GPIO_N_NR, - .label = "GPN", - }, - }, { - .base = S5P64X0_GPP_BASE, - .config = &s5p64x0_gpio_cfgs[5], - .chip = { - .base = S5P6440_GPP(0), - .ngpio = S5P6440_GPIO_P_NR, - .label = "GPP", - }, - }, -}; - -static struct s3c_gpio_chip s5p6450_gpio_4bit[] = { - { - .base = S5P64X0_GPA_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6450_GPA(0), - .ngpio = S5P6450_GPIO_A_NR, - .label = "GPA", - }, - }, { - .base = S5P64X0_GPB_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6450_GPB(0), - .ngpio = S5P6450_GPIO_B_NR, - .label = "GPB", - }, - }, { - .base = S5P64X0_GPC_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6450_GPC(0), - .ngpio = S5P6450_GPIO_C_NR, - .label = "GPC", - }, - }, { - .base = S5P6450_GPD_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6450_GPD(0), - .ngpio = S5P6450_GPIO_D_NR, - .label = "GPD", - }, - }, { - .base = S5P6450_GPK_BASE, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6450_GPK(0), - .ngpio = S5P6450_GPIO_K_NR, - .label = "GPK", - }, - }, -}; - -static struct s3c_gpio_chip s5p6450_gpio_4bit2[] = { - { - .base = S5P64X0_GPG_BASE + 0x4, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6450_GPG(0), - .ngpio = S5P6450_GPIO_G_NR, - .label = "GPG", - }, - }, { - .base = S5P64X0_GPH_BASE + 0x4, - .config = &s5p64x0_gpio_cfgs[1], - .chip = { - .base = S5P6450_GPH(0), - .ngpio = S5P6450_GPIO_H_NR, - .label = "GPH", - }, - }, -}; - -static struct s3c_gpio_chip s5p6450_gpio_rbank_4bit2[] = { - { - .base = S5P64X0_GPR_BASE + 0x4, - .config = &s5p64x0_gpio_cfgs[2], - .chip = { - .base = S5P6450_GPR(0), - .ngpio = S5P6450_GPIO_R_NR, - .label = "GPR", - }, - }, -}; - -static struct s3c_gpio_chip s5p6450_gpio_2bit[] = { - { - .base = S5P64X0_GPF_BASE, - .config = &s5p64x0_gpio_cfgs[5], - .chip = { - .base = S5P6450_GPF(0), - .ngpio = S5P6450_GPIO_F_NR, - .label = "GPF", - }, - }, { - .base = S5P64X0_GPI_BASE, - .config = &s5p64x0_gpio_cfgs[3], - .chip = { - .base = S5P6450_GPI(0), - .ngpio = S5P6450_GPIO_I_NR, - .label = "GPI", - }, - }, { - .base = S5P64X0_GPJ_BASE, - .config = &s5p64x0_gpio_cfgs[3], - .chip = { - .base = S5P6450_GPJ(0), - .ngpio = S5P6450_GPIO_J_NR, - .label = "GPJ", - }, - }, { - .base = S5P64X0_GPN_BASE, - .config = &s5p64x0_gpio_cfgs[4], - .chip = { - .base = S5P6450_GPN(0), - .ngpio = S5P6450_GPIO_N_NR, - .label = "GPN", - }, - }, { - .base = S5P64X0_GPP_BASE, - .config = &s5p64x0_gpio_cfgs[5], - .chip = { - .base = S5P6450_GPP(0), - .ngpio = S5P6450_GPIO_P_NR, - .label = "GPP", - }, - }, { - .base = S5P6450_GPQ_BASE, - .config = &s5p64x0_gpio_cfgs[4], - .chip = { - .base = S5P6450_GPQ(0), - .ngpio = S5P6450_GPIO_Q_NR, - .label = "GPQ", - }, - }, { - .base = S5P6450_GPS_BASE, - .config = &s5p64x0_gpio_cfgs[5], - .chip = { - .base = S5P6450_GPS(0), - .ngpio = S5P6450_GPIO_S_NR, - .label = "GPS", - }, - }, -}; - -void __init s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips) -{ - for (; nr_chips > 0; nr_chips--, chipcfg++) { - if (!chipcfg->set_config) - chipcfg->set_config = s3c_gpio_setcfg_s3c64xx_4bit; - if (!chipcfg->get_config) - chipcfg->get_config = s3c_gpio_getcfg_s3c64xx_4bit; - if (!chipcfg->set_pull) - chipcfg->set_pull = s3c_gpio_setpull_updown; - if (!chipcfg->get_pull) - chipcfg->get_pull = s3c_gpio_getpull_updown; - } -} - -static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip, - int nr_chips) -{ - for (; nr_chips > 0; nr_chips--, chip++) { - chip->chip.direction_input = s5p64x0_gpiolib_rbank_4bit2_input; - chip->chip.direction_output = - s5p64x0_gpiolib_rbank_4bit2_output; - s3c_gpiolib_add(chip); - } -} - -static int __init s5p64x0_gpiolib_init(void) -{ - unsigned int chipid; - - chipid = __raw_readl(S5P64X0_SYS_ID); - - s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs, - ARRAY_SIZE(s5p64x0_gpio_cfgs)); - - if ((chipid & 0xff000) == 0x50000) { - samsung_gpiolib_add_2bit_chips(s5p6450_gpio_2bit, - ARRAY_SIZE(s5p6450_gpio_2bit)); - - samsung_gpiolib_add_4bit_chips(s5p6450_gpio_4bit, - ARRAY_SIZE(s5p6450_gpio_4bit)); - - samsung_gpiolib_add_4bit2_chips(s5p6450_gpio_4bit2, - ARRAY_SIZE(s5p6450_gpio_4bit2)); - - s5p64x0_gpio_add_rbank_4bit2(s5p6450_gpio_rbank_4bit2, - ARRAY_SIZE(s5p6450_gpio_rbank_4bit2)); - } else { - samsung_gpiolib_add_2bit_chips(s5p6440_gpio_2bit, - ARRAY_SIZE(s5p6440_gpio_2bit)); - - samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit, - ARRAY_SIZE(s5p6440_gpio_4bit)); - - samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2, - ARRAY_SIZE(s5p6440_gpio_4bit2)); - - s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2, - ARRAY_SIZE(s5p6440_gpio_rbank_4bit2)); - } - - return 0; -} -core_initcall(s5p64x0_gpiolib_init); diff --git a/drivers/gpio/gpio-s5pc100.c b/drivers/gpio/gpio-s5pc100.c deleted file mode 100644 index 7f87b0c76e0b..000000000000 --- a/drivers/gpio/gpio-s5pc100.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * S5PC100 - GPIOlib support - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Copyright 2009 Samsung Electronics Co - * Kyungmin Park - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* S5PC100 GPIO bank summary: - * - * Bank GPIOs Style INT Type - * A0 8 4Bit GPIO_INT0 - * A1 5 4Bit GPIO_INT1 - * B 8 4Bit GPIO_INT2 - * C 5 4Bit GPIO_INT3 - * D 7 4Bit GPIO_INT4 - * E0 8 4Bit GPIO_INT5 - * E1 6 4Bit GPIO_INT6 - * F0 8 4Bit GPIO_INT7 - * F1 8 4Bit GPIO_INT8 - * F2 8 4Bit GPIO_INT9 - * F3 4 4Bit GPIO_INT10 - * G0 8 4Bit GPIO_INT11 - * G1 3 4Bit GPIO_INT12 - * G2 7 4Bit GPIO_INT13 - * G3 7 4Bit GPIO_INT14 - * H0 8 4Bit WKUP_INT - * H1 8 4Bit WKUP_INT - * H2 8 4Bit WKUP_INT - * H3 8 4Bit WKUP_INT - * I 8 4Bit GPIO_INT15 - * J0 8 4Bit GPIO_INT16 - * J1 5 4Bit GPIO_INT17 - * J2 8 4Bit GPIO_INT18 - * J3 8 4Bit GPIO_INT19 - * J4 4 4Bit GPIO_INT20 - * K0 8 4Bit None - * K1 6 4Bit None - * K2 8 4Bit None - * K3 8 4Bit None - * L0 8 4Bit None - * L1 8 4Bit None - * L2 8 4Bit None - * L3 8 4Bit None - */ - -static struct s3c_gpio_cfg gpio_cfg = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_cfg_eint = { - .cfg_eint = 0xf, - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_cfg_noint = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -/* - * GPIO bank's base address given the index of the bank in the - * list of all gpio banks. - */ -#define S5PC100_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)) - -/* - * Following are the gpio banks in S5PC100. - * - * The 'config' member when left to NULL, is initialized to the default - * structure gpio_cfg in the init function below. - * - * The 'base' member is also initialized in the init function below. - * Note: The initialization of 'base' member of s3c_gpio_chip structure - * uses the above macro and depends on the banks being listed in order here. - */ -static struct s3c_gpio_chip s5pc100_gpio_chips[] = { - { - .chip = { - .base = S5PC100_GPA0(0), - .ngpio = S5PC100_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = S5PC100_GPA1(0), - .ngpio = S5PC100_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = S5PC100_GPB(0), - .ngpio = S5PC100_GPIO_B_NR, - .label = "GPB", - }, - }, { - .chip = { - .base = S5PC100_GPC(0), - .ngpio = S5PC100_GPIO_C_NR, - .label = "GPC", - }, - }, { - .chip = { - .base = S5PC100_GPD(0), - .ngpio = S5PC100_GPIO_D_NR, - .label = "GPD", - }, - }, { - .chip = { - .base = S5PC100_GPE0(0), - .ngpio = S5PC100_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = S5PC100_GPE1(0), - .ngpio = S5PC100_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = S5PC100_GPF0(0), - .ngpio = S5PC100_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = S5PC100_GPF1(0), - .ngpio = S5PC100_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = S5PC100_GPF2(0), - .ngpio = S5PC100_GPIO_F2_NR, - .label = "GPF2", - }, - }, { - .chip = { - .base = S5PC100_GPF3(0), - .ngpio = S5PC100_GPIO_F3_NR, - .label = "GPF3", - }, - }, { - .chip = { - .base = S5PC100_GPG0(0), - .ngpio = S5PC100_GPIO_G0_NR, - .label = "GPG0", - }, - }, { - .chip = { - .base = S5PC100_GPG1(0), - .ngpio = S5PC100_GPIO_G1_NR, - .label = "GPG1", - }, - }, { - .chip = { - .base = S5PC100_GPG2(0), - .ngpio = S5PC100_GPIO_G2_NR, - .label = "GPG2", - }, - }, { - .chip = { - .base = S5PC100_GPG3(0), - .ngpio = S5PC100_GPIO_G3_NR, - .label = "GPG3", - }, - }, { - .chip = { - .base = S5PC100_GPI(0), - .ngpio = S5PC100_GPIO_I_NR, - .label = "GPI", - }, - }, { - .chip = { - .base = S5PC100_GPJ0(0), - .ngpio = S5PC100_GPIO_J0_NR, - .label = "GPJ0", - }, - }, { - .chip = { - .base = S5PC100_GPJ1(0), - .ngpio = S5PC100_GPIO_J1_NR, - .label = "GPJ1", - }, - }, { - .chip = { - .base = S5PC100_GPJ2(0), - .ngpio = S5PC100_GPIO_J2_NR, - .label = "GPJ2", - }, - }, { - .chip = { - .base = S5PC100_GPJ3(0), - .ngpio = S5PC100_GPIO_J3_NR, - .label = "GPJ3", - }, - }, { - .chip = { - .base = S5PC100_GPJ4(0), - .ngpio = S5PC100_GPIO_J4_NR, - .label = "GPJ4", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPK0(0), - .ngpio = S5PC100_GPIO_K0_NR, - .label = "GPK0", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPK1(0), - .ngpio = S5PC100_GPIO_K1_NR, - .label = "GPK1", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPK2(0), - .ngpio = S5PC100_GPIO_K2_NR, - .label = "GPK2", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPK3(0), - .ngpio = S5PC100_GPIO_K3_NR, - .label = "GPK3", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL0(0), - .ngpio = S5PC100_GPIO_L0_NR, - .label = "GPL0", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL1(0), - .ngpio = S5PC100_GPIO_L1_NR, - .label = "GPL1", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL2(0), - .ngpio = S5PC100_GPIO_L2_NR, - .label = "GPL2", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL3(0), - .ngpio = S5PC100_GPIO_L3_NR, - .label = "GPL3", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PC100_GPL4(0), - .ngpio = S5PC100_GPIO_L4_NR, - .label = "GPL4", - }, - }, { - .base = (S5P_VA_GPIO + 0xC00), - .config = &gpio_cfg_eint, - .irq_base = IRQ_EINT(0), - .chip = { - .base = S5PC100_GPH0(0), - .ngpio = S5PC100_GPIO_H0_NR, - .label = "GPH0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC20), - .config = &gpio_cfg_eint, - .irq_base = IRQ_EINT(8), - .chip = { - .base = S5PC100_GPH1(0), - .ngpio = S5PC100_GPIO_H1_NR, - .label = "GPH1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC40), - .config = &gpio_cfg_eint, - .irq_base = IRQ_EINT(16), - .chip = { - .base = S5PC100_GPH2(0), - .ngpio = S5PC100_GPIO_H2_NR, - .label = "GPH2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC60), - .config = &gpio_cfg_eint, - .irq_base = IRQ_EINT(24), - .chip = { - .base = S5PC100_GPH3(0), - .ngpio = S5PC100_GPIO_H3_NR, - .label = "GPH3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; - -static __init int s5pc100_gpiolib_init(void) -{ - struct s3c_gpio_chip *chip = s5pc100_gpio_chips; - int nr_chips = ARRAY_SIZE(s5pc100_gpio_chips); - int gpioint_group = 0; - int i; - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - chip->group = gpioint_group++; - } - if (chip->base == NULL) - chip->base = S5PC100_BANK_BASE(i); - } - - samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips); - s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); - - return 0; -} -core_initcall(s5pc100_gpiolib_init); diff --git a/drivers/gpio/gpio-s5pv210.c b/drivers/gpio/gpio-s5pv210.c deleted file mode 100644 index eb12f1602de9..000000000000 --- a/drivers/gpio/gpio-s5pv210.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * S5PV210 - GPIOlib support - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct s3c_gpio_cfg gpio_cfg = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -static struct s3c_gpio_cfg gpio_cfg_noint = { - .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, -}; - -/* GPIO bank's base address given the index of the bank in the - * list of all gpio banks. - */ -#define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)) - -/* - * Following are the gpio banks in v210. - * - * The 'config' member when left to NULL, is initialized to the default - * structure gpio_cfg in the init function below. - * - * The 'base' member is also initialized in the init function below. - * Note: The initialization of 'base' member of s3c_gpio_chip structure - * uses the above macro and depends on the banks being listed in order here. - */ -static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { - { - .chip = { - .base = S5PV210_GPA0(0), - .ngpio = S5PV210_GPIO_A0_NR, - .label = "GPA0", - }, - }, { - .chip = { - .base = S5PV210_GPA1(0), - .ngpio = S5PV210_GPIO_A1_NR, - .label = "GPA1", - }, - }, { - .chip = { - .base = S5PV210_GPB(0), - .ngpio = S5PV210_GPIO_B_NR, - .label = "GPB", - }, - }, { - .chip = { - .base = S5PV210_GPC0(0), - .ngpio = S5PV210_GPIO_C0_NR, - .label = "GPC0", - }, - }, { - .chip = { - .base = S5PV210_GPC1(0), - .ngpio = S5PV210_GPIO_C1_NR, - .label = "GPC1", - }, - }, { - .chip = { - .base = S5PV210_GPD0(0), - .ngpio = S5PV210_GPIO_D0_NR, - .label = "GPD0", - }, - }, { - .chip = { - .base = S5PV210_GPD1(0), - .ngpio = S5PV210_GPIO_D1_NR, - .label = "GPD1", - }, - }, { - .chip = { - .base = S5PV210_GPE0(0), - .ngpio = S5PV210_GPIO_E0_NR, - .label = "GPE0", - }, - }, { - .chip = { - .base = S5PV210_GPE1(0), - .ngpio = S5PV210_GPIO_E1_NR, - .label = "GPE1", - }, - }, { - .chip = { - .base = S5PV210_GPF0(0), - .ngpio = S5PV210_GPIO_F0_NR, - .label = "GPF0", - }, - }, { - .chip = { - .base = S5PV210_GPF1(0), - .ngpio = S5PV210_GPIO_F1_NR, - .label = "GPF1", - }, - }, { - .chip = { - .base = S5PV210_GPF2(0), - .ngpio = S5PV210_GPIO_F2_NR, - .label = "GPF2", - }, - }, { - .chip = { - .base = S5PV210_GPF3(0), - .ngpio = S5PV210_GPIO_F3_NR, - .label = "GPF3", - }, - }, { - .chip = { - .base = S5PV210_GPG0(0), - .ngpio = S5PV210_GPIO_G0_NR, - .label = "GPG0", - }, - }, { - .chip = { - .base = S5PV210_GPG1(0), - .ngpio = S5PV210_GPIO_G1_NR, - .label = "GPG1", - }, - }, { - .chip = { - .base = S5PV210_GPG2(0), - .ngpio = S5PV210_GPIO_G2_NR, - .label = "GPG2", - }, - }, { - .chip = { - .base = S5PV210_GPG3(0), - .ngpio = S5PV210_GPIO_G3_NR, - .label = "GPG3", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_GPI(0), - .ngpio = S5PV210_GPIO_I_NR, - .label = "GPI", - }, - }, { - .chip = { - .base = S5PV210_GPJ0(0), - .ngpio = S5PV210_GPIO_J0_NR, - .label = "GPJ0", - }, - }, { - .chip = { - .base = S5PV210_GPJ1(0), - .ngpio = S5PV210_GPIO_J1_NR, - .label = "GPJ1", - }, - }, { - .chip = { - .base = S5PV210_GPJ2(0), - .ngpio = S5PV210_GPIO_J2_NR, - .label = "GPJ2", - }, - }, { - .chip = { - .base = S5PV210_GPJ3(0), - .ngpio = S5PV210_GPIO_J3_NR, - .label = "GPJ3", - }, - }, { - .chip = { - .base = S5PV210_GPJ4(0), - .ngpio = S5PV210_GPIO_J4_NR, - .label = "GPJ4", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP01(0), - .ngpio = S5PV210_GPIO_MP01_NR, - .label = "MP01", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP02(0), - .ngpio = S5PV210_GPIO_MP02_NR, - .label = "MP02", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP03(0), - .ngpio = S5PV210_GPIO_MP03_NR, - .label = "MP03", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP04(0), - .ngpio = S5PV210_GPIO_MP04_NR, - .label = "MP04", - }, - }, { - .config = &gpio_cfg_noint, - .chip = { - .base = S5PV210_MP05(0), - .ngpio = S5PV210_GPIO_MP05_NR, - .label = "MP05", - }, - }, { - .base = (S5P_VA_GPIO + 0xC00), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(0), - .chip = { - .base = S5PV210_GPH0(0), - .ngpio = S5PV210_GPIO_H0_NR, - .label = "GPH0", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC20), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(8), - .chip = { - .base = S5PV210_GPH1(0), - .ngpio = S5PV210_GPIO_H1_NR, - .label = "GPH1", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC40), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(16), - .chip = { - .base = S5PV210_GPH2(0), - .ngpio = S5PV210_GPIO_H2_NR, - .label = "GPH2", - .to_irq = samsung_gpiolib_to_irq, - }, - }, { - .base = (S5P_VA_GPIO + 0xC60), - .config = &gpio_cfg_noint, - .irq_base = IRQ_EINT(24), - .chip = { - .base = S5PV210_GPH3(0), - .ngpio = S5PV210_GPIO_H3_NR, - .label = "GPH3", - .to_irq = samsung_gpiolib_to_irq, - }, - }, -}; - -static __init int s5pv210_gpiolib_init(void) -{ - struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; - int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); - int gpioint_group = 0; - int i = 0; - - for (i = 0; i < nr_chips; i++, chip++) { - if (chip->config == NULL) { - chip->config = &gpio_cfg; - chip->group = gpioint_group++; - } - if (chip->base == NULL) - chip->base = S5PV210_BANK_BASE(i); - } - - samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); - s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); - - return 0; -} -core_initcall(s5pv210_gpiolib_init); diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c new file mode 100644 index 000000000000..36f3675e7de8 --- /dev/null +++ b/drivers/gpio/gpio-samsung.c @@ -0,0 +1,2686 @@ +/* + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * SAMSUNG - GPIOlib support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef DEBUG_GPIO +#define gpio_dbg(x...) do { } while (0) +#else +#define gpio_dbg(x...) printk(KERN_DEBUG x) +#endif + +int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + void __iomem *reg = chip->base + 0x08; + int shift = off * 2; + u32 pup; + + pup = __raw_readl(reg); + pup &= ~(3 << shift); + pup |= pull << shift; + __raw_writel(pup, reg); + + return 0; +} + +samsung_gpio_pull_t samsung_gpio_getpull_updown(struct samsung_gpio_chip *chip, + unsigned int off) +{ + void __iomem *reg = chip->base + 0x08; + int shift = off * 2; + u32 pup = __raw_readl(reg); + + pup >>= shift; + pup &= 0x3; + + return (__force samsung_gpio_pull_t)pup; +} + +int s3c2443_gpio_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + switch (pull) { + case S3C_GPIO_PULL_NONE: + pull = 0x01; + break; + case S3C_GPIO_PULL_UP: + pull = 0x00; + break; + case S3C_GPIO_PULL_DOWN: + pull = 0x02; + break; + } + return samsung_gpio_setpull_updown(chip, off, pull); +} + +samsung_gpio_pull_t s3c2443_gpio_getpull(struct samsung_gpio_chip *chip, + unsigned int off) +{ + samsung_gpio_pull_t pull; + + pull = samsung_gpio_getpull_updown(chip, off); + + switch (pull) { + case 0x00: + pull = S3C_GPIO_PULL_UP; + break; + case 0x01: + case 0x03: + pull = S3C_GPIO_PULL_NONE; + break; + case 0x02: + pull = S3C_GPIO_PULL_DOWN; + break; + } + + return pull; +} + +static int s3c24xx_gpio_setpull_1(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull, + samsung_gpio_pull_t updown) +{ + void __iomem *reg = chip->base + 0x08; + u32 pup = __raw_readl(reg); + + if (pull == updown) + pup &= ~(1 << off); + else if (pull == S3C_GPIO_PULL_NONE) + pup |= (1 << off); + else + return -EINVAL; + + __raw_writel(pup, reg); + return 0; +} + +static samsung_gpio_pull_t s3c24xx_gpio_getpull_1(struct samsung_gpio_chip *chip, + unsigned int off, + samsung_gpio_pull_t updown) +{ + void __iomem *reg = chip->base + 0x08; + u32 pup = __raw_readl(reg); + + pup &= (1 << off); + return pup ? S3C_GPIO_PULL_NONE : updown; +} + +samsung_gpio_pull_t s3c24xx_gpio_getpull_1up(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return s3c24xx_gpio_getpull_1(chip, off, S3C_GPIO_PULL_UP); +} + +int s3c24xx_gpio_setpull_1up(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_UP); +} + +samsung_gpio_pull_t s3c24xx_gpio_getpull_1down(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return s3c24xx_gpio_getpull_1(chip, off, S3C_GPIO_PULL_DOWN); +} + +int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); +} + +static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + if (pull == S3C_GPIO_PULL_UP) + pull = 3; + + return samsung_gpio_setpull_updown(chip, off, pull); +} + +static samsung_gpio_pull_t exynos4_gpio_getpull(struct samsung_gpio_chip *chip, + unsigned int off) +{ + samsung_gpio_pull_t pull; + + pull = samsung_gpio_getpull_updown(chip, off); + + if (pull == 3) + pull = S3C_GPIO_PULL_UP; + + return pull; +} + +/* + * samsung_gpio_setcfg_2bit - Samsung 2bit style GPIO configuration. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register + * has two bits of configuration per gpio, which have the following + * functions: + * 00 = input + * 01 = output + * 1x = special function + */ + +static int samsung_gpio_setcfg_2bit(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = off * 2; + u32 con; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + if (cfg > 3) + return -EINVAL; + + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0x3 << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * samsung_gpio_getcfg_2bit - Samsung 2bit style GPIO configuration read. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of samsung_gpio_setcfg_2bit(). Will return a value whicg + * could be directly passed back to samsung_gpio_setcfg_2bit(), from the + * S3C_GPIO_SPECIAL() macro. + */ + +static unsigned int samsung_gpio_getcfg_2bit(struct samsung_gpio_chip *chip, + unsigned int off) +{ + u32 con; + + con = __raw_readl(chip->base); + con >>= off * 2; + con &= 3; + + /* this conversion works for IN and OUT as well as special mode */ + return S3C_GPIO_SPECIAL(con); +} + +/* + * samsung_gpio_setcfg_4bit - Samsung 4bit single register GPIO config. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register has 4 bits + * of control per GPIO, generally in the form of: + * 0000 = Input + * 0001 = Output + * others = Special functions (dependent on bank) + * + * Note, since the code to deal with the case where there are two control + * registers instead of one, we do not have a separate set of functions for + * each case. + */ + +static int samsung_gpio_setcfg_4bit(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = (off & 7) * 4; + u32 con; + + if (off < 8 && chip->chip.ngpio > 8) + reg -= 4; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0xf << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * samsung_gpio_getcfg_4bit - Samsung 4bit single register GPIO config read. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of samsung_gpio_setcfg_4bit(), turning a gpio configuration + * register setting into a value the software can use, such as could be passed + * to samsung_gpio_setcfg_4bit(). + * + * @sa samsung_gpio_getcfg_2bit + */ + +static unsigned samsung_gpio_getcfg_4bit(struct samsung_gpio_chip *chip, + unsigned int off) +{ + void __iomem *reg = chip->base; + unsigned int shift = (off & 7) * 4; + u32 con; + + if (off < 8 && chip->chip.ngpio > 8) + reg -= 4; + + con = __raw_readl(reg); + con >>= shift; + con &= 0xf; + + /* this conversion works for IN and OUT as well as special mode */ + return S3C_GPIO_SPECIAL(con); +} + +/* + * s3c24xx_gpio_setcfg_abank - S3C24XX style GPIO configuration (Bank A) + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register + * has one bit of configuration for the gpio, where setting the bit + * means the pin is in special function mode and unset means output. + */ + +static int s3c24xx_gpio_setcfg_abank(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = off; + u32 con; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + + /* Map output to 0, and SFN2 to 1 */ + cfg -= 1; + if (cfg > 1) + return -EINVAL; + + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0x1 << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * s3c24xx_gpio_getcfg_abank - S3C24XX style GPIO configuration read (Bank A) + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of s3c24xx_gpio_setcfg_abank() turning an GPIO into a usable + * GPIO configuration value. + * + * @sa samsung_gpio_getcfg_2bit + * @sa samsung_gpio_getcfg_4bit + */ + +static unsigned s3c24xx_gpio_getcfg_abank(struct samsung_gpio_chip *chip, + unsigned int off) +{ + u32 con; + + con = __raw_readl(chip->base); + con >>= off; + con &= 1; + con++; + + return S3C_GPIO_SFN(con); +} + +static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift; + u32 con; + + switch (off) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + shift = (off & 7) * 4; + reg -= 4; + break; + case 6: + shift = ((off + 1) & 7) * 4; + reg -= 4; + default: + shift = ((off + 1) & 7) * 4; + break; + } + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0xf << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +static void __init samsung_gpiolib_set_cfg(struct samsung_gpio_cfg *chipcfg, + int nr_chips) +{ + for (; nr_chips > 0; nr_chips--, chipcfg++) { + if (!chipcfg->set_config) + chipcfg->set_config = samsung_gpio_setcfg_4bit; + if (!chipcfg->get_config) + chipcfg->get_config = samsung_gpio_getcfg_4bit; + if (!chipcfg->set_pull) + chipcfg->set_pull = samsung_gpio_setpull_updown; + if (!chipcfg->get_pull) + chipcfg->get_pull = samsung_gpio_getpull_updown; + } +} + +struct samsung_gpio_cfg s3c24xx_gpiocfg_default = { + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, +}; + +static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { + .set_config = s3c24xx_gpio_setcfg_abank, + .get_config = s3c24xx_gpio_getcfg_abank, +}; + +static struct samsung_gpio_cfg exynos4_gpio_cfg = { + .set_pull = exynos4_gpio_setpull, + .get_pull = exynos4_gpio_getpull, +}; + +static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = { + .cfg_eint = 0x3, + .set_config = s5p64x0_gpio_setcfg_rbank, + .get_config = samsung_gpio_getcfg_4bit, + .set_pull = samsung_gpio_setpull_updown, + .get_pull = samsung_gpio_getpull_updown, +}; + +static struct samsung_gpio_cfg samsung_gpio_cfgs[] = { + { + .cfg_eint = 0x0, + }, { + .cfg_eint = 0x3, + }, { + .cfg_eint = 0x7, + }, { + .cfg_eint = 0xF, + }, { + .cfg_eint = 0x0, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, { + .cfg_eint = 0x2, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, { + .cfg_eint = 0x3, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, { + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, +}; + +/* + * Default routines for controlling GPIO, based on the original S3C24XX + * GPIO functions which deal with the case where each gpio bank of the + * chip is as following: + * + * base + 0x00: Control register, 2 bits per gpio + * gpio n: 2 bits starting at (2*n) + * 00 = input, 01 = output, others mean special-function + * base + 0x04: Data register, 1 bit per gpio + * bit n: data bit n +*/ + +static int samsung_gpiolib_2bit_input(struct gpio_chip *chip, unsigned offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long con; + + samsung_gpio_lock(ourchip, flags); + + con = __raw_readl(base + 0x00); + con &= ~(3 << (offset * 2)); + + __raw_writel(con, base + 0x00); + + samsung_gpio_unlock(ourchip, flags); + return 0; +} + +static int samsung_gpiolib_2bit_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + unsigned long con; + + samsung_gpio_lock(ourchip, flags); + + dat = __raw_readl(base + 0x04); + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + __raw_writel(dat, base + 0x04); + + con = __raw_readl(base + 0x00); + con &= ~(3 << (offset * 2)); + con |= 1 << (offset * 2); + + __raw_writel(con, base + 0x00); + __raw_writel(dat, base + 0x04); + + samsung_gpio_unlock(ourchip, flags); + return 0; +} + +/* + * The samsung_gpiolib_4bit routines are to control the gpio banks where + * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the + * following example: + * + * base + 0x00: Control register, 4 bits per gpio + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x04: Data register, 1 bit per gpio + * bit n: data bit n + * + * Note, since the data register is one bit per gpio and is at base + 0x4 + * we can use samsung_gpiolib_get and samsung_gpiolib_set to change the + * state of the output. + */ + +static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long con; + + con = __raw_readl(base + GPIOCON_OFF); + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, base + GPIOCON_OFF); + + gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); + + return 0; +} + +static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long con; + unsigned long dat; + + con = __raw_readl(base + GPIOCON_OFF); + con &= ~(0xf << con_4bit_shift(offset)); + con |= 0x1 << con_4bit_shift(offset); + + dat = __raw_readl(base + GPIODAT_OFF); + + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(dat, base + GPIODAT_OFF); + __raw_writel(con, base + GPIOCON_OFF); + __raw_writel(dat, base + GPIODAT_OFF); + + gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + + return 0; +} + +/* + * The next set of routines are for the case where the GPIO configuration + * registers are 4 bits per GPIO but there is more than one register (the + * bank has more than 8 GPIOs. + * + * This case is the similar to the 4 bit case, but the registers are as + * follows: + * + * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs) + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs) + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x08: Data register, 1 bit per gpio + * bit n: data bit n + * + * To allow us to use the samsung_gpiolib_get and samsung_gpiolib_set + * routines we store the 'base + 0x4' address so that these routines see + * the data register at ourchip->base + 0x04. + */ + +static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + + if (offset > 7) + offset -= 8; + else + regcon -= 4; + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, regcon); + + gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con); + + return 0; +} + +static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + unsigned long dat; + unsigned con_offset = offset; + + if (con_offset > 7) + con_offset -= 8; + else + regcon -= 4; + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(con_offset)); + con |= 0x1 << con_4bit_shift(con_offset); + + dat = __raw_readl(base + GPIODAT_OFF); + + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(dat, base + GPIODAT_OFF); + __raw_writel(con, regcon); + __raw_writel(dat, base + GPIODAT_OFF); + + gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + + return 0; +} + +/* The next set of routines are for the case of s3c24xx bank a */ + +static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset) +{ + return -EINVAL; +} + +static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + unsigned long con; + + local_irq_save(flags); + + con = __raw_readl(base + 0x00); + dat = __raw_readl(base + 0x04); + + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + + __raw_writel(dat, base + 0x04); + + con &= ~(1 << offset); + + __raw_writel(con, base + 0x00); + __raw_writel(dat, base + 0x04); + + local_irq_restore(flags); + return 0; +} + +/* The next set of routines are for the case of s5p64x0 bank r */ + +static int s5p64x0_gpiolib_rbank_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + unsigned long flags; + + switch (offset) { + case 6: + offset += 1; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + regcon -= 4; + break; + default: + offset -= 7; + break; + } + + samsung_gpio_lock(ourchip, flags); + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, regcon); + + samsung_gpio_unlock(ourchip, flags); + + return 0; +} + +static int s5p64x0_gpiolib_rbank_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + unsigned long dat; + unsigned long flags; + unsigned con_offset = offset; + + switch (con_offset) { + case 6: + con_offset += 1; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + regcon -= 4; + break; + default: + con_offset -= 7; + break; + } + + samsung_gpio_lock(ourchip, flags); + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(con_offset)); + con |= 0x1 << con_4bit_shift(con_offset); + + dat = __raw_readl(base + GPIODAT_OFF); + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(con, regcon); + __raw_writel(dat, base + GPIODAT_OFF); + + samsung_gpio_unlock(ourchip, flags); + + return 0; +} + +static void samsung_gpiolib_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + + samsung_gpio_lock(ourchip, flags); + + dat = __raw_readl(base + 0x04); + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + __raw_writel(dat, base + 0x04); + + samsung_gpio_unlock(ourchip, flags); +} + +static int samsung_gpiolib_get(struct gpio_chip *chip, unsigned offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + unsigned long val; + + val = __raw_readl(ourchip->base + 0x04); + val >>= offset; + val &= 1; + + return val; +} + +/* + * CONFIG_S3C_GPIO_TRACK enables the tracking of the s3c specific gpios + * for use with the configuration calls, and other parts of the s3c gpiolib + * support code. + * + * Not all s3c support code will need this, as some configurations of cpu + * may only support one or two different configuration options and have an + * easy gpio to samsung_gpio_chip mapping function. If this is the case, then + * the machine support file should provide its own samsung_gpiolib_getchip() + * and any other necessary functions. + */ + +#ifdef CONFIG_S3C_GPIO_TRACK +struct samsung_gpio_chip *s3c_gpios[S3C_GPIO_END]; + +static __init void s3c_gpiolib_track(struct samsung_gpio_chip *chip) +{ + unsigned int gpn; + int i; + + gpn = chip->chip.base; + for (i = 0; i < chip->chip.ngpio; i++, gpn++) { + BUG_ON(gpn >= ARRAY_SIZE(s3c_gpios)); + s3c_gpios[gpn] = chip; + } +} +#endif /* CONFIG_S3C_GPIO_TRACK */ + +/* + * samsung_gpiolib_add() - add the Samsung gpio_chip. + * @chip: The chip to register + * + * This is a wrapper to gpiochip_add() that takes our specific gpio chip + * information and makes the necessary alterations for the platform and + * notes the information for use with the configuration systems and any + * other parts of the system. + */ + +static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) +{ + struct gpio_chip *gc = &chip->chip; + int ret; + + BUG_ON(!chip->base); + BUG_ON(!gc->label); + BUG_ON(!gc->ngpio); + + spin_lock_init(&chip->lock); + + if (!gc->direction_input) + gc->direction_input = samsung_gpiolib_2bit_input; + if (!gc->direction_output) + gc->direction_output = samsung_gpiolib_2bit_output; + if (!gc->set) + gc->set = samsung_gpiolib_set; + if (!gc->get) + gc->get = samsung_gpiolib_get; + +#ifdef CONFIG_PM + if (chip->pm != NULL) { + if (!chip->pm->save || !chip->pm->resume) + printk(KERN_ERR "gpio: %s has missing PM functions\n", + gc->label); + } else + printk(KERN_ERR "gpio: %s has no PM function\n", gc->label); +#endif + + /* gpiochip_add() prints own failure message on error. */ + ret = gpiochip_add(gc); + if (ret >= 0) + s3c_gpiolib_track(chip); +} + +static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base) +{ + int i; + struct gpio_chip *gc = &chip->chip; + + for (i = 0 ; i < nr_chips; i++, chip++) { + if (!chip->config) + chip->config = &s3c24xx_gpiocfg_default; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_2bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * 0x10); + + if (!gc->direction_input) + gc->direction_input = samsung_gpiolib_2bit_input; + if (!gc->direction_output) + gc->direction_output = samsung_gpiolib_2bit_output; + + samsung_gpiolib_add(chip); + } +} + +static void __init samsung_gpiolib_add_2bit_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base, + unsigned int offset) +{ + int i; + + for (i = 0 ; i < nr_chips; i++, chip++) { + chip->chip.direction_input = samsung_gpiolib_2bit_input; + chip->chip.direction_output = samsung_gpiolib_2bit_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[7]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_2bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * offset); + + samsung_gpiolib_add(chip); + } +} + +/* + * samsung_gpiolib_add_4bit_chips - 4bit single register GPIO config. + * @chip: The gpio chip that is being configured. + * @nr_chips: The no of chips (gpio ports) for the GPIO being configured. + * + * This helper deal with the GPIO cases where the control register has 4 bits + * of control per GPIO, generally in the form of: + * 0000 = Input + * 0001 = Output + * others = Special functions (dependent on bank) + * + * Note, since the code to deal with the case where there are two control + * registers instead of one, we do not have a separate set of function + * (samsung_gpiolib_add_4bit2_chips)for each case. + */ + +static void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base) +{ + int i; + + for (i = 0 ; i < nr_chips; i++, chip++) { + chip->chip.direction_input = samsung_gpiolib_4bit_input; + chip->chip.direction_output = samsung_gpiolib_4bit_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[2]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * 0x20); + + samsung_gpiolib_add(chip); + } +} + +static void __init samsung_gpiolib_add_4bit2_chips(struct samsung_gpio_chip *chip, + int nr_chips) +{ + for (; nr_chips > 0; nr_chips--, chip++) { + chip->chip.direction_input = samsung_gpiolib_4bit2_input; + chip->chip.direction_output = samsung_gpiolib_4bit2_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[2]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); + + samsung_gpiolib_add(chip); + } +} + +static void __init s5p64x0_gpiolib_add_rbank(struct samsung_gpio_chip *chip, + int nr_chips) +{ + for (; nr_chips > 0; nr_chips--, chip++) { + chip->chip.direction_input = s5p64x0_gpiolib_rbank_input; + chip->chip.direction_output = s5p64x0_gpiolib_rbank_output; + + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); + + samsung_gpiolib_add(chip); + } +} + +int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct samsung_gpio_chip *samsung_chip = container_of(chip, struct samsung_gpio_chip, chip); + + return samsung_chip->irq_base + offset; +} + +#ifdef CONFIG_PLAT_S3C24XX +static int s3c24xx_gpiolib_fbank_to_irq(struct gpio_chip *chip, unsigned offset) +{ + if (offset < 4) + return IRQ_EINT0 + offset; + + if (offset < 8) + return IRQ_EINT4 + offset - 4; + + return -EINVAL; +} +#endif + +#ifdef CONFIG_PLAT_S3C64XX +static int s3c64xx_gpiolib_mbank_to_irq(struct gpio_chip *chip, unsigned pin) +{ + return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO; +} + +static int s3c64xx_gpiolib_lbank_to_irq(struct gpio_chip *chip, unsigned pin) +{ + return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO; +} +#endif + +struct samsung_gpio_chip s3c24xx_gpios[] = { +#ifdef CONFIG_PLAT_S3C24XX + { + .config = &s3c24xx_gpiocfg_banka, + .chip = { + .base = S3C2410_GPA(0), + .owner = THIS_MODULE, + .label = "GPIOA", + .ngpio = 24, + .direction_input = s3c24xx_gpiolib_banka_input, + .direction_output = s3c24xx_gpiolib_banka_output, + }, + }, { + .chip = { + .base = S3C2410_GPB(0), + .owner = THIS_MODULE, + .label = "GPIOB", + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPC(0), + .owner = THIS_MODULE, + .label = "GPIOC", + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPD(0), + .owner = THIS_MODULE, + .label = "GPIOD", + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPE(0), + .label = "GPIOE", + .owner = THIS_MODULE, + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPF(0), + .owner = THIS_MODULE, + .label = "GPIOF", + .ngpio = 8, + .to_irq = s3c24xx_gpiolib_fbank_to_irq, + }, + }, { + .irq_base = IRQ_EINT8, + .chip = { + .base = S3C2410_GPG(0), + .owner = THIS_MODULE, + .label = "GPIOG", + .ngpio = 16, + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .chip = { + .base = S3C2410_GPH(0), + .owner = THIS_MODULE, + .label = "GPIOH", + .ngpio = 11, + }, + }, + /* GPIOS for the S3C2443 and later devices. */ + { + .base = S3C2440_GPJCON, + .chip = { + .base = S3C2410_GPJ(0), + .owner = THIS_MODULE, + .label = "GPIOJ", + .ngpio = 16, + }, + }, { + .base = S3C2443_GPKCON, + .chip = { + .base = S3C2410_GPK(0), + .owner = THIS_MODULE, + .label = "GPIOK", + .ngpio = 16, + }, + }, { + .base = S3C2443_GPLCON, + .chip = { + .base = S3C2410_GPL(0), + .owner = THIS_MODULE, + .label = "GPIOL", + .ngpio = 15, + }, + }, { + .base = S3C2443_GPMCON, + .chip = { + .base = S3C2410_GPM(0), + .owner = THIS_MODULE, + .label = "GPIOM", + .ngpio = 2, + }, + }, +#endif +}; + +/* + * GPIO bank summary: + * + * Bank GPIOs Style SlpCon ExtInt Group + * A 8 4Bit Yes 1 + * B 7 4Bit Yes 1 + * C 8 4Bit Yes 2 + * D 5 4Bit Yes 3 + * E 5 4Bit Yes None + * F 16 2Bit Yes 4 [1] + * G 7 4Bit Yes 5 + * H 10 4Bit[2] Yes 6 + * I 16 2Bit Yes None + * J 12 2Bit Yes None + * K 16 4Bit[2] No None + * L 15 4Bit[2] No None + * M 6 4Bit No IRQ_EINT + * N 16 2Bit No IRQ_EINT + * O 16 2Bit Yes 7 + * P 15 2Bit Yes 8 + * Q 9 2Bit Yes 9 + * + * [1] BANKF pins 14,15 do not form part of the external interrupt sources + * [2] BANK has two control registers, GPxCON0 and GPxCON1 + */ + +static struct samsung_gpio_chip s3c64xx_gpios_4bit[] = { +#ifdef CONFIG_PLAT_S3C64XX + { + .chip = { + .base = S3C64XX_GPA(0), + .ngpio = S3C64XX_GPIO_A_NR, + .label = "GPA", + }, + }, { + .chip = { + .base = S3C64XX_GPB(0), + .ngpio = S3C64XX_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S3C64XX_GPC(0), + .ngpio = S3C64XX_GPIO_C_NR, + .label = "GPC", + }, + }, { + .chip = { + .base = S3C64XX_GPD(0), + .ngpio = S3C64XX_GPIO_D_NR, + .label = "GPD", + }, + }, { + .config = &samsung_gpio_cfgs[0], + .chip = { + .base = S3C64XX_GPE(0), + .ngpio = S3C64XX_GPIO_E_NR, + .label = "GPE", + }, + }, { + .base = S3C64XX_GPG_BASE, + .chip = { + .base = S3C64XX_GPG(0), + .ngpio = S3C64XX_GPIO_G_NR, + .label = "GPG", + }, + }, { + .base = S3C64XX_GPM_BASE, + .config = &samsung_gpio_cfgs[1], + .chip = { + .base = S3C64XX_GPM(0), + .ngpio = S3C64XX_GPIO_M_NR, + .label = "GPM", + .to_irq = s3c64xx_gpiolib_mbank_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip s3c64xx_gpios_4bit2[] = { +#ifdef CONFIG_PLAT_S3C64XX + { + .base = S3C64XX_GPH_BASE + 0x4, + .chip = { + .base = S3C64XX_GPH(0), + .ngpio = S3C64XX_GPIO_H_NR, + .label = "GPH", + }, + }, { + .base = S3C64XX_GPK_BASE + 0x4, + .config = &samsung_gpio_cfgs[0], + .chip = { + .base = S3C64XX_GPK(0), + .ngpio = S3C64XX_GPIO_K_NR, + .label = "GPK", + }, + }, { + .base = S3C64XX_GPL_BASE + 0x4, + .config = &samsung_gpio_cfgs[1], + .chip = { + .base = S3C64XX_GPL(0), + .ngpio = S3C64XX_GPIO_L_NR, + .label = "GPL", + .to_irq = s3c64xx_gpiolib_lbank_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip s3c64xx_gpios_2bit[] = { +#ifdef CONFIG_PLAT_S3C64XX + { + .base = S3C64XX_GPF_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPF(0), + .ngpio = S3C64XX_GPIO_F_NR, + .label = "GPF", + }, + }, { + .config = &samsung_gpio_cfgs[7], + .chip = { + .base = S3C64XX_GPI(0), + .ngpio = S3C64XX_GPIO_I_NR, + .label = "GPI", + }, + }, { + .config = &samsung_gpio_cfgs[7], + .chip = { + .base = S3C64XX_GPJ(0), + .ngpio = S3C64XX_GPIO_J_NR, + .label = "GPJ", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPO(0), + .ngpio = S3C64XX_GPIO_O_NR, + .label = "GPO", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPP(0), + .ngpio = S3C64XX_GPIO_P_NR, + .label = "GPP", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPQ(0), + .ngpio = S3C64XX_GPIO_Q_NR, + .label = "GPQ", + }, + }, { + .base = S3C64XX_GPN_BASE, + .irq_base = IRQ_EINT(0), + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S3C64XX_GPN(0), + .ngpio = S3C64XX_GPIO_N_NR, + .label = "GPN", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +/* + * S5P6440 GPIO bank summary: + * + * Bank GPIOs Style SlpCon ExtInt Group + * A 6 4Bit Yes 1 + * B 7 4Bit Yes 1 + * C 8 4Bit Yes 2 + * F 2 2Bit Yes 4 [1] + * G 7 4Bit Yes 5 + * H 10 4Bit[2] Yes 6 + * I 16 2Bit Yes None + * J 12 2Bit Yes None + * N 16 2Bit No IRQ_EINT + * P 8 2Bit Yes 8 + * R 15 4Bit[2] Yes 8 + */ + +static struct samsung_gpio_chip s5p6440_gpios_4bit[] = { +#ifdef CONFIG_CPU_S5P6440 + { + .chip = { + .base = S5P6440_GPA(0), + .ngpio = S5P6440_GPIO_A_NR, + .label = "GPA", + }, + }, { + .chip = { + .base = S5P6440_GPB(0), + .ngpio = S5P6440_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S5P6440_GPC(0), + .ngpio = S5P6440_GPIO_C_NR, + .label = "GPC", + }, + }, { + .base = S5P64X0_GPG_BASE, + .chip = { + .base = S5P6440_GPG(0), + .ngpio = S5P6440_GPIO_G_NR, + .label = "GPG", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6440_gpios_4bit2[] = { +#ifdef CONFIG_CPU_S5P6440 + { + .base = S5P64X0_GPH_BASE + 0x4, + .chip = { + .base = S5P6440_GPH(0), + .ngpio = S5P6440_GPIO_H_NR, + .label = "GPH", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6440_gpios_rbank[] = { +#ifdef CONFIG_CPU_S5P6440 + { + .base = S5P64X0_GPR_BASE + 0x4, + .config = &s5p64x0_gpio_cfg_rbank, + .chip = { + .base = S5P6440_GPR(0), + .ngpio = S5P6440_GPIO_R_NR, + .label = "GPR", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6440_gpios_2bit[] = { +#ifdef CONFIG_CPU_S5P6440 + { + .base = S5P64X0_GPF_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6440_GPF(0), + .ngpio = S5P6440_GPIO_F_NR, + .label = "GPF", + }, + }, { + .base = S5P64X0_GPI_BASE, + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = S5P6440_GPI(0), + .ngpio = S5P6440_GPIO_I_NR, + .label = "GPI", + }, + }, { + .base = S5P64X0_GPJ_BASE, + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = S5P6440_GPJ(0), + .ngpio = S5P6440_GPIO_J_NR, + .label = "GPJ", + }, + }, { + .base = S5P64X0_GPN_BASE, + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S5P6440_GPN(0), + .ngpio = S5P6440_GPIO_N_NR, + .label = "GPN", + }, + }, { + .base = S5P64X0_GPP_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6440_GPP(0), + .ngpio = S5P6440_GPIO_P_NR, + .label = "GPP", + }, + }, +#endif +}; + +/* + * S5P6450 GPIO bank summary: + * + * Bank GPIOs Style SlpCon ExtInt Group + * A 6 4Bit Yes 1 + * B 7 4Bit Yes 1 + * C 8 4Bit Yes 2 + * D 8 4Bit Yes None + * F 2 2Bit Yes None + * G 14 4Bit[2] Yes 5 + * H 10 4Bit[2] Yes 6 + * I 16 2Bit Yes None + * J 12 2Bit Yes None + * K 5 4Bit Yes None + * N 16 2Bit No IRQ_EINT + * P 11 2Bit Yes 8 + * Q 14 2Bit Yes None + * R 15 4Bit[2] Yes None + * S 8 2Bit Yes None + * + * [1] BANKF pins 14,15 do not form part of the external interrupt sources + * [2] BANK has two control registers, GPxCON0 and GPxCON1 + */ + +static struct samsung_gpio_chip s5p6450_gpios_4bit[] = { +#ifdef CONFIG_CPU_S5P6450 + { + .chip = { + .base = S5P6450_GPA(0), + .ngpio = S5P6450_GPIO_A_NR, + .label = "GPA", + }, + }, { + .chip = { + .base = S5P6450_GPB(0), + .ngpio = S5P6450_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S5P6450_GPC(0), + .ngpio = S5P6450_GPIO_C_NR, + .label = "GPC", + }, + }, { + .chip = { + .base = S5P6450_GPD(0), + .ngpio = S5P6450_GPIO_D_NR, + .label = "GPD", + }, + }, { + .base = S5P6450_GPK_BASE, + .chip = { + .base = S5P6450_GPK(0), + .ngpio = S5P6450_GPIO_K_NR, + .label = "GPK", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6450_gpios_4bit2[] = { +#ifdef CONFIG_CPU_S5P6450 + { + .base = S5P64X0_GPG_BASE + 0x4, + .chip = { + .base = S5P6450_GPG(0), + .ngpio = S5P6450_GPIO_G_NR, + .label = "GPG", + }, + }, { + .base = S5P64X0_GPH_BASE + 0x4, + .chip = { + .base = S5P6450_GPH(0), + .ngpio = S5P6450_GPIO_H_NR, + .label = "GPH", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6450_gpios_rbank[] = { +#ifdef CONFIG_CPU_S5P6450 + { + .base = S5P64X0_GPR_BASE + 0x4, + .config = &s5p64x0_gpio_cfg_rbank, + .chip = { + .base = S5P6450_GPR(0), + .ngpio = S5P6450_GPIO_R_NR, + .label = "GPR", + }, + }, +#endif +}; + +static struct samsung_gpio_chip s5p6450_gpios_2bit[] = { +#ifdef CONFIG_CPU_S5P6450 + { + .base = S5P64X0_GPF_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6450_GPF(0), + .ngpio = S5P6450_GPIO_F_NR, + .label = "GPF", + }, + }, { + .base = S5P64X0_GPI_BASE, + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = S5P6450_GPI(0), + .ngpio = S5P6450_GPIO_I_NR, + .label = "GPI", + }, + }, { + .base = S5P64X0_GPJ_BASE, + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = S5P6450_GPJ(0), + .ngpio = S5P6450_GPIO_J_NR, + .label = "GPJ", + }, + }, { + .base = S5P64X0_GPN_BASE, + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S5P6450_GPN(0), + .ngpio = S5P6450_GPIO_N_NR, + .label = "GPN", + }, + }, { + .base = S5P64X0_GPP_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6450_GPP(0), + .ngpio = S5P6450_GPIO_P_NR, + .label = "GPP", + }, + }, { + .base = S5P6450_GPQ_BASE, + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S5P6450_GPQ(0), + .ngpio = S5P6450_GPIO_Q_NR, + .label = "GPQ", + }, + }, { + .base = S5P6450_GPS_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S5P6450_GPS(0), + .ngpio = S5P6450_GPIO_S_NR, + .label = "GPS", + }, + }, +#endif +}; + +/* + * S5PC100 GPIO bank summary: + * + * Bank GPIOs Style INT Type + * A0 8 4Bit GPIO_INT0 + * A1 5 4Bit GPIO_INT1 + * B 8 4Bit GPIO_INT2 + * C 5 4Bit GPIO_INT3 + * D 7 4Bit GPIO_INT4 + * E0 8 4Bit GPIO_INT5 + * E1 6 4Bit GPIO_INT6 + * F0 8 4Bit GPIO_INT7 + * F1 8 4Bit GPIO_INT8 + * F2 8 4Bit GPIO_INT9 + * F3 4 4Bit GPIO_INT10 + * G0 8 4Bit GPIO_INT11 + * G1 3 4Bit GPIO_INT12 + * G2 7 4Bit GPIO_INT13 + * G3 7 4Bit GPIO_INT14 + * H0 8 4Bit WKUP_INT + * H1 8 4Bit WKUP_INT + * H2 8 4Bit WKUP_INT + * H3 8 4Bit WKUP_INT + * I 8 4Bit GPIO_INT15 + * J0 8 4Bit GPIO_INT16 + * J1 5 4Bit GPIO_INT17 + * J2 8 4Bit GPIO_INT18 + * J3 8 4Bit GPIO_INT19 + * J4 4 4Bit GPIO_INT20 + * K0 8 4Bit None + * K1 6 4Bit None + * K2 8 4Bit None + * K3 8 4Bit None + * L0 8 4Bit None + * L1 8 4Bit None + * L2 8 4Bit None + * L3 8 4Bit None + */ + +static struct samsung_gpio_chip s5pc100_gpios_4bit[] = { +#ifdef CONFIG_CPU_S5PC100 + { + .chip = { + .base = S5PC100_GPA0(0), + .ngpio = S5PC100_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .chip = { + .base = S5PC100_GPA1(0), + .ngpio = S5PC100_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .chip = { + .base = S5PC100_GPB(0), + .ngpio = S5PC100_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S5PC100_GPC(0), + .ngpio = S5PC100_GPIO_C_NR, + .label = "GPC", + }, + }, { + .chip = { + .base = S5PC100_GPD(0), + .ngpio = S5PC100_GPIO_D_NR, + .label = "GPD", + }, + }, { + .chip = { + .base = S5PC100_GPE0(0), + .ngpio = S5PC100_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .chip = { + .base = S5PC100_GPE1(0), + .ngpio = S5PC100_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .chip = { + .base = S5PC100_GPF0(0), + .ngpio = S5PC100_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .chip = { + .base = S5PC100_GPF1(0), + .ngpio = S5PC100_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .chip = { + .base = S5PC100_GPF2(0), + .ngpio = S5PC100_GPIO_F2_NR, + .label = "GPF2", + }, + }, { + .chip = { + .base = S5PC100_GPF3(0), + .ngpio = S5PC100_GPIO_F3_NR, + .label = "GPF3", + }, + }, { + .chip = { + .base = S5PC100_GPG0(0), + .ngpio = S5PC100_GPIO_G0_NR, + .label = "GPG0", + }, + }, { + .chip = { + .base = S5PC100_GPG1(0), + .ngpio = S5PC100_GPIO_G1_NR, + .label = "GPG1", + }, + }, { + .chip = { + .base = S5PC100_GPG2(0), + .ngpio = S5PC100_GPIO_G2_NR, + .label = "GPG2", + }, + }, { + .chip = { + .base = S5PC100_GPG3(0), + .ngpio = S5PC100_GPIO_G3_NR, + .label = "GPG3", + }, + }, { + .chip = { + .base = S5PC100_GPI(0), + .ngpio = S5PC100_GPIO_I_NR, + .label = "GPI", + }, + }, { + .chip = { + .base = S5PC100_GPJ0(0), + .ngpio = S5PC100_GPIO_J0_NR, + .label = "GPJ0", + }, + }, { + .chip = { + .base = S5PC100_GPJ1(0), + .ngpio = S5PC100_GPIO_J1_NR, + .label = "GPJ1", + }, + }, { + .chip = { + .base = S5PC100_GPJ2(0), + .ngpio = S5PC100_GPIO_J2_NR, + .label = "GPJ2", + }, + }, { + .chip = { + .base = S5PC100_GPJ3(0), + .ngpio = S5PC100_GPIO_J3_NR, + .label = "GPJ3", + }, + }, { + .chip = { + .base = S5PC100_GPJ4(0), + .ngpio = S5PC100_GPIO_J4_NR, + .label = "GPJ4", + }, + }, { + .chip = { + .base = S5PC100_GPK0(0), + .ngpio = S5PC100_GPIO_K0_NR, + .label = "GPK0", + }, + }, { + .chip = { + .base = S5PC100_GPK1(0), + .ngpio = S5PC100_GPIO_K1_NR, + .label = "GPK1", + }, + }, { + .chip = { + .base = S5PC100_GPK2(0), + .ngpio = S5PC100_GPIO_K2_NR, + .label = "GPK2", + }, + }, { + .chip = { + .base = S5PC100_GPK3(0), + .ngpio = S5PC100_GPIO_K3_NR, + .label = "GPK3", + }, + }, { + .chip = { + .base = S5PC100_GPL0(0), + .ngpio = S5PC100_GPIO_L0_NR, + .label = "GPL0", + }, + }, { + .chip = { + .base = S5PC100_GPL1(0), + .ngpio = S5PC100_GPIO_L1_NR, + .label = "GPL1", + }, + }, { + .chip = { + .base = S5PC100_GPL2(0), + .ngpio = S5PC100_GPIO_L2_NR, + .label = "GPL2", + }, + }, { + .chip = { + .base = S5PC100_GPL3(0), + .ngpio = S5PC100_GPIO_L3_NR, + .label = "GPL3", + }, + }, { + .chip = { + .base = S5PC100_GPL4(0), + .ngpio = S5PC100_GPIO_L4_NR, + .label = "GPL4", + }, + }, { + .base = (S5P_VA_GPIO + 0xC00), + .irq_base = IRQ_EINT(0), + .chip = { + .base = S5PC100_GPH0(0), + .ngpio = S5PC100_GPIO_H0_NR, + .label = "GPH0", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC20), + .irq_base = IRQ_EINT(8), + .chip = { + .base = S5PC100_GPH1(0), + .ngpio = S5PC100_GPIO_H1_NR, + .label = "GPH1", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC40), + .irq_base = IRQ_EINT(16), + .chip = { + .base = S5PC100_GPH2(0), + .ngpio = S5PC100_GPIO_H2_NR, + .label = "GPH2", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC60), + .irq_base = IRQ_EINT(24), + .chip = { + .base = S5PC100_GPH3(0), + .ngpio = S5PC100_GPIO_H3_NR, + .label = "GPH3", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +/* + * Followings are the gpio banks in S5PV210/S5PC110 + * + * The 'config' member when left to NULL, is initialized to the default + * structure samsung_gpio_cfgs[4] in the init function below. + * + * The 'base' member is also initialized in the init function below. + * Note: The initialization of 'base' member of samsung_gpio_chip structure + * uses the above macro and depends on the banks being listed in order here. + */ + +static struct samsung_gpio_chip s5pv210_gpios_4bit[] = { +#ifdef CONFIG_CPU_S5PV210 + { + .chip = { + .base = S5PV210_GPA0(0), + .ngpio = S5PV210_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .chip = { + .base = S5PV210_GPA1(0), + .ngpio = S5PV210_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .chip = { + .base = S5PV210_GPB(0), + .ngpio = S5PV210_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S5PV210_GPC0(0), + .ngpio = S5PV210_GPIO_C0_NR, + .label = "GPC0", + }, + }, { + .chip = { + .base = S5PV210_GPC1(0), + .ngpio = S5PV210_GPIO_C1_NR, + .label = "GPC1", + }, + }, { + .chip = { + .base = S5PV210_GPD0(0), + .ngpio = S5PV210_GPIO_D0_NR, + .label = "GPD0", + }, + }, { + .chip = { + .base = S5PV210_GPD1(0), + .ngpio = S5PV210_GPIO_D1_NR, + .label = "GPD1", + }, + }, { + .chip = { + .base = S5PV210_GPE0(0), + .ngpio = S5PV210_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .chip = { + .base = S5PV210_GPE1(0), + .ngpio = S5PV210_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .chip = { + .base = S5PV210_GPF0(0), + .ngpio = S5PV210_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .chip = { + .base = S5PV210_GPF1(0), + .ngpio = S5PV210_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .chip = { + .base = S5PV210_GPF2(0), + .ngpio = S5PV210_GPIO_F2_NR, + .label = "GPF2", + }, + }, { + .chip = { + .base = S5PV210_GPF3(0), + .ngpio = S5PV210_GPIO_F3_NR, + .label = "GPF3", + }, + }, { + .chip = { + .base = S5PV210_GPG0(0), + .ngpio = S5PV210_GPIO_G0_NR, + .label = "GPG0", + }, + }, { + .chip = { + .base = S5PV210_GPG1(0), + .ngpio = S5PV210_GPIO_G1_NR, + .label = "GPG1", + }, + }, { + .chip = { + .base = S5PV210_GPG2(0), + .ngpio = S5PV210_GPIO_G2_NR, + .label = "GPG2", + }, + }, { + .chip = { + .base = S5PV210_GPG3(0), + .ngpio = S5PV210_GPIO_G3_NR, + .label = "GPG3", + }, + }, { + .chip = { + .base = S5PV210_GPI(0), + .ngpio = S5PV210_GPIO_I_NR, + .label = "GPI", + }, + }, { + .chip = { + .base = S5PV210_GPJ0(0), + .ngpio = S5PV210_GPIO_J0_NR, + .label = "GPJ0", + }, + }, { + .chip = { + .base = S5PV210_GPJ1(0), + .ngpio = S5PV210_GPIO_J1_NR, + .label = "GPJ1", + }, + }, { + .chip = { + .base = S5PV210_GPJ2(0), + .ngpio = S5PV210_GPIO_J2_NR, + .label = "GPJ2", + }, + }, { + .chip = { + .base = S5PV210_GPJ3(0), + .ngpio = S5PV210_GPIO_J3_NR, + .label = "GPJ3", + }, + }, { + .chip = { + .base = S5PV210_GPJ4(0), + .ngpio = S5PV210_GPIO_J4_NR, + .label = "GPJ4", + }, + }, { + .chip = { + .base = S5PV210_MP01(0), + .ngpio = S5PV210_GPIO_MP01_NR, + .label = "MP01", + }, + }, { + .chip = { + .base = S5PV210_MP02(0), + .ngpio = S5PV210_GPIO_MP02_NR, + .label = "MP02", + }, + }, { + .chip = { + .base = S5PV210_MP03(0), + .ngpio = S5PV210_GPIO_MP03_NR, + .label = "MP03", + }, + }, { + .chip = { + .base = S5PV210_MP04(0), + .ngpio = S5PV210_GPIO_MP04_NR, + .label = "MP04", + }, + }, { + .chip = { + .base = S5PV210_MP05(0), + .ngpio = S5PV210_GPIO_MP05_NR, + .label = "MP05", + }, + }, { + .base = (S5P_VA_GPIO + 0xC00), + .irq_base = IRQ_EINT(0), + .chip = { + .base = S5PV210_GPH0(0), + .ngpio = S5PV210_GPIO_H0_NR, + .label = "GPH0", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC20), + .irq_base = IRQ_EINT(8), + .chip = { + .base = S5PV210_GPH1(0), + .ngpio = S5PV210_GPIO_H1_NR, + .label = "GPH1", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC40), + .irq_base = IRQ_EINT(16), + .chip = { + .base = S5PV210_GPH2(0), + .ngpio = S5PV210_GPIO_H2_NR, + .label = "GPH2", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO + 0xC60), + .irq_base = IRQ_EINT(24), + .chip = { + .base = S5PV210_GPH3(0), + .ngpio = S5PV210_GPIO_H3_NR, + .label = "GPH3", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +/* + * Followings are the gpio banks in EXYNOS4210 + * + * The 'config' member when left to NULL, is initialized to the default + * structure samsung_gpio_cfgs[4] in the init function below. + * + * The 'base' member is also initialized in the init function below. + * Note: The initialization of 'base' member of samsung_gpio_chip structure + * uses the above macro and depends on the banks being listed in order here. + */ + +static struct samsung_gpio_chip exynos4_gpios_1[] = { +#ifdef CONFIG_ARCH_EXYNOS4 + { + .chip = { + .base = EXYNOS4_GPA0(0), + .ngpio = EXYNOS4_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .chip = { + .base = EXYNOS4_GPA1(0), + .ngpio = EXYNOS4_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .chip = { + .base = EXYNOS4_GPB(0), + .ngpio = EXYNOS4_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = EXYNOS4_GPC0(0), + .ngpio = EXYNOS4_GPIO_C0_NR, + .label = "GPC0", + }, + }, { + .chip = { + .base = EXYNOS4_GPC1(0), + .ngpio = EXYNOS4_GPIO_C1_NR, + .label = "GPC1", + }, + }, { + .chip = { + .base = EXYNOS4_GPD0(0), + .ngpio = EXYNOS4_GPIO_D0_NR, + .label = "GPD0", + }, + }, { + .chip = { + .base = EXYNOS4_GPD1(0), + .ngpio = EXYNOS4_GPIO_D1_NR, + .label = "GPD1", + }, + }, { + .chip = { + .base = EXYNOS4_GPE0(0), + .ngpio = EXYNOS4_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .chip = { + .base = EXYNOS4_GPE1(0), + .ngpio = EXYNOS4_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .chip = { + .base = EXYNOS4_GPE2(0), + .ngpio = EXYNOS4_GPIO_E2_NR, + .label = "GPE2", + }, + }, { + .chip = { + .base = EXYNOS4_GPE3(0), + .ngpio = EXYNOS4_GPIO_E3_NR, + .label = "GPE3", + }, + }, { + .chip = { + .base = EXYNOS4_GPE4(0), + .ngpio = EXYNOS4_GPIO_E4_NR, + .label = "GPE4", + }, + }, { + .chip = { + .base = EXYNOS4_GPF0(0), + .ngpio = EXYNOS4_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .chip = { + .base = EXYNOS4_GPF1(0), + .ngpio = EXYNOS4_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .chip = { + .base = EXYNOS4_GPF2(0), + .ngpio = EXYNOS4_GPIO_F2_NR, + .label = "GPF2", + }, + }, { + .chip = { + .base = EXYNOS4_GPF3(0), + .ngpio = EXYNOS4_GPIO_F3_NR, + .label = "GPF3", + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos4_gpios_2[] = { +#ifdef CONFIG_ARCH_EXYNOS4 + { + .chip = { + .base = EXYNOS4_GPJ0(0), + .ngpio = EXYNOS4_GPIO_J0_NR, + .label = "GPJ0", + }, + }, { + .chip = { + .base = EXYNOS4_GPJ1(0), + .ngpio = EXYNOS4_GPIO_J1_NR, + .label = "GPJ1", + }, + }, { + .chip = { + .base = EXYNOS4_GPK0(0), + .ngpio = EXYNOS4_GPIO_K0_NR, + .label = "GPK0", + }, + }, { + .chip = { + .base = EXYNOS4_GPK1(0), + .ngpio = EXYNOS4_GPIO_K1_NR, + .label = "GPK1", + }, + }, { + .chip = { + .base = EXYNOS4_GPK2(0), + .ngpio = EXYNOS4_GPIO_K2_NR, + .label = "GPK2", + }, + }, { + .chip = { + .base = EXYNOS4_GPK3(0), + .ngpio = EXYNOS4_GPIO_K3_NR, + .label = "GPK3", + }, + }, { + .chip = { + .base = EXYNOS4_GPL0(0), + .ngpio = EXYNOS4_GPIO_L0_NR, + .label = "GPL0", + }, + }, { + .chip = { + .base = EXYNOS4_GPL1(0), + .ngpio = EXYNOS4_GPIO_L1_NR, + .label = "GPL1", + }, + }, { + .chip = { + .base = EXYNOS4_GPL2(0), + .ngpio = EXYNOS4_GPIO_L2_NR, + .label = "GPL2", + }, + }, { + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = EXYNOS4_GPY0(0), + .ngpio = EXYNOS4_GPIO_Y0_NR, + .label = "GPY0", + }, + }, { + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = EXYNOS4_GPY1(0), + .ngpio = EXYNOS4_GPIO_Y1_NR, + .label = "GPY1", + }, + }, { + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = EXYNOS4_GPY2(0), + .ngpio = EXYNOS4_GPIO_Y2_NR, + .label = "GPY2", + }, + }, { + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = EXYNOS4_GPY3(0), + .ngpio = EXYNOS4_GPIO_Y3_NR, + .label = "GPY3", + }, + }, { + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = EXYNOS4_GPY4(0), + .ngpio = EXYNOS4_GPIO_Y4_NR, + .label = "GPY4", + }, + }, { + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = EXYNOS4_GPY5(0), + .ngpio = EXYNOS4_GPIO_Y5_NR, + .label = "GPY5", + }, + }, { + .config = &samsung_gpio_cfgs[4], + .chip = { + .base = EXYNOS4_GPY6(0), + .ngpio = EXYNOS4_GPIO_Y6_NR, + .label = "GPY6", + }, + }, { + .base = (S5P_VA_GPIO2 + 0xC00), + .config = &samsung_gpio_cfgs[4], + .irq_base = IRQ_EINT(0), + .chip = { + .base = EXYNOS4_GPX0(0), + .ngpio = EXYNOS4_GPIO_X0_NR, + .label = "GPX0", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO2 + 0xC20), + .config = &samsung_gpio_cfgs[4], + .irq_base = IRQ_EINT(8), + .chip = { + .base = EXYNOS4_GPX1(0), + .ngpio = EXYNOS4_GPIO_X1_NR, + .label = "GPX1", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO2 + 0xC40), + .config = &samsung_gpio_cfgs[4], + .irq_base = IRQ_EINT(16), + .chip = { + .base = EXYNOS4_GPX2(0), + .ngpio = EXYNOS4_GPIO_X2_NR, + .label = "GPX2", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .base = (S5P_VA_GPIO2 + 0xC60), + .config = &samsung_gpio_cfgs[4], + .irq_base = IRQ_EINT(24), + .chip = { + .base = EXYNOS4_GPX3(0), + .ngpio = EXYNOS4_GPIO_X3_NR, + .label = "GPX3", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos4_gpios_3[] = { +#ifdef CONFIG_ARCH_EXYNOS4 + { + .chip = { + .base = EXYNOS4_GPZ(0), + .ngpio = EXYNOS4_GPIO_Z_NR, + .label = "GPZ", + }, + }, +#endif +}; + +/* TODO: cleanup soc_is_* */ +static __init int samsung_gpiolib_init(void) +{ + struct samsung_gpio_chip *chip; + int i, nr_chips; + int group = 0; + + samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); + + if (soc_is_s3c24xx()) { + s3c24xx_gpiolib_add_chips(s3c24xx_gpios, + ARRAY_SIZE(s3c24xx_gpios), S3C24XX_VA_GPIO); + } else if (soc_is_s3c64xx()) { + samsung_gpiolib_add_2bit_chips(s3c64xx_gpios_2bit, + ARRAY_SIZE(s3c64xx_gpios_2bit), + S3C64XX_VA_GPIO + 0xE0, 0x20); + samsung_gpiolib_add_4bit_chips(s3c64xx_gpios_4bit, + ARRAY_SIZE(s3c64xx_gpios_4bit), + S3C64XX_VA_GPIO); + samsung_gpiolib_add_4bit2_chips(s3c64xx_gpios_4bit2, + ARRAY_SIZE(s3c64xx_gpios_4bit2)); + } else if (soc_is_s5p6440()) { + samsung_gpiolib_add_2bit_chips(s5p6440_gpios_2bit, + ARRAY_SIZE(s5p6440_gpios_2bit), NULL, 0x0); + samsung_gpiolib_add_4bit_chips(s5p6440_gpios_4bit, + ARRAY_SIZE(s5p6440_gpios_4bit), S5P_VA_GPIO); + samsung_gpiolib_add_4bit2_chips(s5p6440_gpios_4bit2, + ARRAY_SIZE(s5p6440_gpios_4bit2)); + s5p64x0_gpiolib_add_rbank(s5p6440_gpios_rbank, + ARRAY_SIZE(s5p6440_gpios_rbank)); + } else if (soc_is_s5p6450()) { + samsung_gpiolib_add_2bit_chips(s5p6450_gpios_2bit, + ARRAY_SIZE(s5p6450_gpios_2bit), NULL, 0x0); + samsung_gpiolib_add_4bit_chips(s5p6450_gpios_4bit, + ARRAY_SIZE(s5p6450_gpios_4bit), S5P_VA_GPIO); + samsung_gpiolib_add_4bit2_chips(s5p6450_gpios_4bit2, + ARRAY_SIZE(s5p6450_gpios_4bit2)); + s5p64x0_gpiolib_add_rbank(s5p6450_gpios_rbank, + ARRAY_SIZE(s5p6450_gpios_rbank)); + } else if (soc_is_s5pc100()) { + group = 0; + chip = s5pc100_gpios_4bit; + nr_chips = ARRAY_SIZE(s5pc100_gpios_4bit); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &samsung_gpio_cfgs[4]; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(s5pc100_gpios_4bit, nr_chips, S5P_VA_GPIO); +#if defined(CONFIG_CPU_S5PC100) && defined(CONFIG_S5P_GPIO_INT) + s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); +#endif + } else if (soc_is_s5pv210()) { + group = 0; + chip = s5pv210_gpios_4bit; + nr_chips = ARRAY_SIZE(s5pv210_gpios_4bit); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &samsung_gpio_cfgs[4]; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(s5pv210_gpios_4bit, nr_chips, S5P_VA_GPIO); +#if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_S5P_GPIO_INT) + s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); +#endif + } else if (soc_is_exynos4210()) { + group = 0; + + /* gpio part1 */ + chip = exynos4_gpios_1; + nr_chips = ARRAY_SIZE(exynos4_gpios_1); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos4_gpio_cfg; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1); + + /* gpio part2 */ + chip = exynos4_gpios_2; + nr_chips = ARRAY_SIZE(exynos4_gpios_2); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos4_gpio_cfg; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2); + + /* gpio part3 */ + chip = exynos4_gpios_3; + nr_chips = ARRAY_SIZE(exynos4_gpios_3); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos4_gpio_cfg; + chip->group = group++; + } + } + samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3); + +#if defined(CONFIG_SOC_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT) + s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); + s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); +#endif + } + + return 0; +} +core_initcall(samsung_gpiolib_init); + +int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset; + int ret; + + if (!chip) + return -EINVAL; + + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_setcfg(chip, offset, config); + samsung_gpio_unlock(chip, flags); + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_cfgpin); + +int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, + unsigned int cfg) +{ + int ret; + + for (; nr > 0; nr--, start++) { + ret = s3c_gpio_cfgpin(start, cfg); + if (ret != 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range); + +int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, + unsigned int cfg, samsung_gpio_pull_t pull) +{ + int ret; + + for (; nr > 0; nr--, start++) { + s3c_gpio_setpull(start, pull); + ret = s3c_gpio_cfgpin(start, cfg); + if (ret != 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range); + +unsigned s3c_gpio_getcfg(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + unsigned ret = 0; + int offset; + + if (chip) { + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_getcfg(chip, offset); + samsung_gpio_unlock(chip, flags); + } + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_getcfg); + +int s3c_gpio_setpull(unsigned int pin, samsung_gpio_pull_t pull) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset, ret; + + if (!chip) + return -EINVAL; + + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_setpull(chip, offset, pull); + samsung_gpio_unlock(chip, flags); + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_setpull); + +samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset; + u32 pup = 0; + + if (chip) { + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + pup = samsung_gpio_do_getpull(chip, offset); + samsung_gpio_unlock(chip, flags); + } + + return (__force samsung_gpio_pull_t)pup; +} +EXPORT_SYMBOL(s3c_gpio_getpull); + +/* gpiolib wrappers until these are totally eliminated */ + +void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) +{ + int ret; + + WARN_ON(to); /* should be none of these left */ + + if (!to) { + /* if pull is enabled, try first with up, and if that + * fails, try using down */ + + ret = s3c_gpio_setpull(pin, S3C_GPIO_PULL_UP); + if (ret) + s3c_gpio_setpull(pin, S3C_GPIO_PULL_DOWN); + } else { + s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE); + } +} +EXPORT_SYMBOL(s3c2410_gpio_pullup); + +void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) +{ + /* do this via gpiolib until all users removed */ + + gpio_request(pin, "temporary"); + gpio_set_value(pin, to); + gpio_free(pin); +} +EXPORT_SYMBOL(s3c2410_gpio_setpin); + +unsigned int s3c2410_gpio_getpin(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long offs = pin - chip->chip.base; + + return __raw_readl(chip->base + 0x04) & (1 << offs); +} +EXPORT_SYMBOL(s3c2410_gpio_getpin); + +#ifdef CONFIG_S5P_GPIO_DRVSTR +s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned int off; + void __iomem *reg; + int shift; + u32 drvstr; + + if (!chip) + return -EINVAL; + + off = pin - chip->chip.base; + shift = off * 2; + reg = chip->base + 0x0C; + + drvstr = __raw_readl(reg); + drvstr = drvstr >> shift; + drvstr &= 0x3; + + return (__force s5p_gpio_drvstr_t)drvstr; +} +EXPORT_SYMBOL(s5p_gpio_get_drvstr); + +int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned int off; + void __iomem *reg; + int shift; + u32 tmp; + + if (!chip) + return -EINVAL; + + off = pin - chip->chip.base; + shift = off * 2; + reg = chip->base + 0x0C; + + tmp = __raw_readl(reg); + tmp &= ~(0x3 << shift); + tmp |= drvstr << shift; + + __raw_writel(tmp, reg); + + return 0; +} +EXPORT_SYMBOL(s5p_gpio_set_drvstr); +#endif /* CONFIG_S5P_GPIO_DRVSTR */ + +#ifdef CONFIG_PLAT_S3C24XX +unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) +{ + unsigned long flags; + unsigned long misccr; + + local_irq_save(flags); + misccr = __raw_readl(S3C24XX_MISCCR); + misccr &= ~clear; + misccr ^= change; + __raw_writel(misccr, S3C24XX_MISCCR); + local_irq_restore(flags); + + return misccr; +} +EXPORT_SYMBOL(s3c2410_modify_misccr); +#endif From 782d8a3c0bdf23ec24fc8facb5af8510b2cf6de1 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Tue, 30 Aug 2011 20:47:32 +0900 Subject: [PATCH 0439/1596] ARM: SAMSUNG: Update the name of regarding Samsung GPIO According to gpio-samsung.c, this patch updates the name of regarding Samsung GPIO. Basically the samsung_xxx prefix is used in gpio-samsung.c instead of s3c_xxx, because unified name can reduce its complexity. Note: some s3c_xxx stil remains because it is used widely. It will be updated next time. Cc: Ben Dooks Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/include/mach/pm-core.h | 2 +- arch/arm/mach-s3c2410/include/mach/gpio-fns.h | 99 +--------- .../mach-s3c2410/include/mach/gpio-track.h | 6 +- arch/arm/mach-s3c2410/include/mach/pm-core.h | 2 +- arch/arm/mach-s3c2410/s3c2410.c | 4 +- arch/arm/mach-s3c2412/gpio.c | 2 +- arch/arm/mach-s3c2416/s3c2416.c | 4 +- arch/arm/mach-s3c2440/s3c2440.c | 4 +- arch/arm/mach-s3c2440/s3c2442.c | 4 +- arch/arm/mach-s3c2443/s3c2443.c | 4 +- arch/arm/mach-s3c64xx/include/mach/pm-core.h | 2 +- arch/arm/mach-s5pv210/include/mach/pm-core.h | 2 +- arch/arm/plat-s5p/irq-gpioint.c | 10 +- .../include/plat/gpio-cfg-helpers.h | 172 +++++------------- arch/arm/plat-samsung/include/plat/gpio-cfg.h | 34 ++-- .../arm/plat-samsung/include/plat/gpio-core.h | 97 +++------- arch/arm/plat-samsung/include/plat/gpio-fns.h | 98 ++++++++++ arch/arm/plat-samsung/include/plat/pm.h | 10 +- arch/arm/plat-samsung/pm-gpio.c | 72 ++++---- arch/arm/plat-samsung/pm.c | 6 +- 20 files changed, 250 insertions(+), 384 deletions(-) create mode 100644 arch/arm/plat-samsung/include/plat/gpio-fns.h diff --git a/arch/arm/mach-exynos4/include/mach/pm-core.h b/arch/arm/mach-exynos4/include/mach/pm-core.h index 1df3b81f96e8..3499ec737206 100644 --- a/arch/arm/mach-exynos4/include/mach/pm-core.h +++ b/arch/arm/mach-exynos4/include/mach/pm-core.h @@ -53,7 +53,7 @@ static inline void s3c_pm_restored_gpios(void) /* nothing here yet */ } -static inline void s3c_pm_saved_gpios(void) +static inline void samsung_pm_saved_gpios(void) { /* nothing here yet */ } diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-fns.h b/arch/arm/mach-s3c2410/include/mach/gpio-fns.h index bab139201761..c53ad34c6579 100644 --- a/arch/arm/mach-s3c2410/include/mach/gpio-fns.h +++ b/arch/arm/mach-s3c2410/include/mach/gpio-fns.h @@ -1,98 +1 @@ -/* arch/arm/mach-s3c2410/include/mach/gpio-fns.h - * - * Copyright (c) 2003-2009 Simtec Electronics - * Ben Dooks - * - * S3C2410 - hardware - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __MACH_GPIO_FNS_H -#define __MACH_GPIO_FNS_H __FILE__ - -/* These functions are in the to-be-removed category and it is strongly - * encouraged not to use these in new code. They will be marked deprecated - * very soon. - * - * Most of the functionality can be either replaced by the gpiocfg calls - * for the s3c platform or by the generic GPIOlib API. - * - * As of 2.6.35-rc, these will be removed, with the few drivers using them - * either replaced or given a wrapper until the calls can be removed. -*/ - -#include - -static inline void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int cfg) -{ - /* 1:1 mapping between cfgpin and setcfg calls at the moment */ - s3c_gpio_cfgpin(pin, cfg); -} - -/* external functions for GPIO support - * - * These allow various different clients to access the same GPIO - * registers without conflicting. If your driver only owns the entire - * GPIO register, then it is safe to ioremap/__raw_{read|write} to it. -*/ - -extern unsigned int s3c2410_gpio_getcfg(unsigned int pin); - -/* s3c2410_gpio_getirq - * - * turn the given pin number into the corresponding IRQ number - * - * returns: - * < 0 = no interrupt for this pin - * >=0 = interrupt number for the pin -*/ - -extern int s3c2410_gpio_getirq(unsigned int pin); - -/* s3c2410_gpio_irqfilter - * - * set the irq filtering on the given pin - * - * on = 0 => disable filtering - * 1 => enable filtering - * - * config = S3C2410_EINTFLT_PCLK or S3C2410_EINTFLT_EXTCLK orred with - * width of filter (0 through 63) - * - * -*/ - -extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, - unsigned int config); - -/* s3c2410_gpio_pullup - * - * This call should be replaced with s3c_gpio_setpull(). - * - * As a note, there is currently no distinction between pull-up and pull-down - * in the s3c24xx series devices with only an on/off configuration. - */ - -/* s3c2410_gpio_pullup - * - * configure the pull-up control on the given pin - * - * to = 1 => disable the pull-up - * 0 => enable the pull-up - * - * eg; - * - * s3c2410_gpio_pullup(S3C2410_GPB(0), 0); - * s3c2410_gpio_pullup(S3C2410_GPE(8), 0); -*/ - -extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to); - -extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to); - -extern unsigned int s3c2410_gpio_getpin(unsigned int pin); - -#endif /* __MACH_GPIO_FNS_H */ +#include diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-track.h b/arch/arm/mach-s3c2410/include/mach/gpio-track.h index d67819dde42a..c410a078622c 100644 --- a/arch/arm/mach-s3c2410/include/mach/gpio-track.h +++ b/arch/arm/mach-s3c2410/include/mach/gpio-track.h @@ -17,11 +17,11 @@ #include -extern struct s3c_gpio_chip s3c24xx_gpios[]; +extern struct samsung_gpio_chip s3c24xx_gpios[]; -static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int pin) +static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int pin) { - struct s3c_gpio_chip *chip; + struct samsung_gpio_chip *chip; if (pin > S3C_GPIO_END) return NULL; diff --git a/arch/arm/mach-s3c2410/include/mach/pm-core.h b/arch/arm/mach-s3c2410/include/mach/pm-core.h index 45eea5210c87..2eef7e6f7675 100644 --- a/arch/arm/mach-s3c2410/include/mach/pm-core.h +++ b/arch/arm/mach-s3c2410/include/mach/pm-core.h @@ -64,4 +64,4 @@ static inline void s3c_pm_arch_update_uart(void __iomem *regs, } static inline void s3c_pm_restored_gpios(void) { } -static inline void s3c_pm_saved_gpios(void) { } +static inline void samsung_pm_saved_gpios(void) { } diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index f1d3bd8f6f17..a99c2f4a523f 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c @@ -72,8 +72,8 @@ void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no) void __init s3c2410_map_io(void) { - s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1up; - s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1up; + s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up; + s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up; iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc)); } diff --git a/arch/arm/mach-s3c2412/gpio.c b/arch/arm/mach-s3c2412/gpio.c index 3404a876b33e..4526f6ba31a8 100644 --- a/arch/arm/mach-s3c2412/gpio.c +++ b/arch/arm/mach-s3c2412/gpio.c @@ -28,7 +28,7 @@ int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state) { - struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); unsigned long offs = pin - chip->chip.base; unsigned long flags; unsigned long slpcon; diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c index 494ce913dc95..3156b7a71371 100644 --- a/arch/arm/mach-s3c2416/s3c2416.c +++ b/arch/arm/mach-s3c2416/s3c2416.c @@ -118,8 +118,8 @@ void __init s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no) void __init s3c2416_map_io(void) { - s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_updown; - s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_updown; + s3c24xx_gpiocfg_default.set_pull = samsung_gpio_setpull_updown; + s3c24xx_gpiocfg_default.get_pull = samsung_gpio_getpull_updown; /* initialize device information early */ s3c2416_default_sdhci0(); diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c index ce99ff72838d..fc84e481efcf 100644 --- a/arch/arm/mach-s3c2440/s3c2440.c +++ b/arch/arm/mach-s3c2440/s3c2440.c @@ -68,6 +68,6 @@ void __init s3c2440_map_io(void) { s3c244x_map_io(); - s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1up; - s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1up; + s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up; + s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up; } diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c2440/s3c2442.c index 9ad99f8016a1..48e273ce9f9a 100644 --- a/arch/arm/mach-s3c2440/s3c2442.c +++ b/arch/arm/mach-s3c2440/s3c2442.c @@ -180,6 +180,6 @@ void __init s3c2442_map_io(void) { s3c244x_map_io(); - s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1down; - s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1down; + s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1down; + s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1down; } diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c index e6a28ba52c7d..5df6458ddd42 100644 --- a/arch/arm/mach-s3c2443/s3c2443.c +++ b/arch/arm/mach-s3c2443/s3c2443.c @@ -90,8 +90,8 @@ void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no) void __init s3c2443_map_io(void) { - s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_s3c2443; - s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_s3c2443; + s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull; + s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull; iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc)); } diff --git a/arch/arm/mach-s3c64xx/include/mach/pm-core.h b/arch/arm/mach-s3c64xx/include/mach/pm-core.h index 38659bebe4b1..fcf3dcabb694 100644 --- a/arch/arm/mach-s3c64xx/include/mach/pm-core.h +++ b/arch/arm/mach-s3c64xx/include/mach/pm-core.h @@ -104,7 +104,7 @@ static inline void s3c_pm_restored_gpios(void) __raw_writel(0, S3C64XX_SLPEN); } -static inline void s3c_pm_saved_gpios(void) +static inline void samsung_pm_saved_gpios(void) { /* turn on the sleep mode and keep it there, as it seems that during * suspend the xCON registers get re-set and thus you can end up with diff --git a/arch/arm/mach-s5pv210/include/mach/pm-core.h b/arch/arm/mach-s5pv210/include/mach/pm-core.h index 3e22109e1b7b..eba8aea63ed8 100644 --- a/arch/arm/mach-s5pv210/include/mach/pm-core.h +++ b/arch/arm/mach-s5pv210/include/mach/pm-core.h @@ -43,4 +43,4 @@ static inline void s3c_pm_arch_update_uart(void __iomem *regs, } static inline void s3c_pm_restored_gpios(void) { } -static inline void s3c_pm_saved_gpios(void) { } +static inline void samsung_pm_saved_gpios(void) { } diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c index f71078ef6bb5..0455519aecdf 100644 --- a/arch/arm/plat-s5p/irq-gpioint.c +++ b/arch/arm/plat-s5p/irq-gpioint.c @@ -37,7 +37,7 @@ struct s5p_gpioint_bank { int start; int nr_groups; int irq; - struct s3c_gpio_chip **chips; + struct samsung_gpio_chip **chips; void (*handler)(unsigned int, struct irq_desc *); }; @@ -87,7 +87,7 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) chained_irq_enter(chip, desc); for (group = 0; group < bank->nr_groups; group++) { - struct s3c_gpio_chip *chip = bank->chips[group]; + struct samsung_gpio_chip *chip = bank->chips[group]; if (!chip) continue; @@ -110,7 +110,7 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } -static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) +static __init int s5p_gpioint_add(struct samsung_gpio_chip *chip) { static int used_gpioint_groups = 0; int group = chip->group; @@ -130,7 +130,7 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) return -EINVAL; if (!bank->handler) { - bank->chips = kzalloc(sizeof(struct s3c_gpio_chip *) * + bank->chips = kzalloc(sizeof(struct samsung_gpio_chip *) * bank->nr_groups, GFP_KERNEL); if (!bank->chips) return -ENOMEM; @@ -173,7 +173,7 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) int __init s5p_register_gpio_interrupt(int pin) { - struct s3c_gpio_chip *my_chip = s3c_gpiolib_getchip(pin); + struct samsung_gpio_chip *my_chip = samsung_gpiolib_getchip(pin); int offset, group; int ret; diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h index 9a4e53d52967..a181d7ce81cf 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h @@ -1,11 +1,11 @@ -/* linux/arch/arm/plat-s3c/include/plat/gpio-cfg-helper.h +/* linux/arch/arm/plat-samsung/include/plat/gpio-cfg-helper.h * * Copyright 2008 Openmoko, Inc. * Copyright 2008 Simtec Electronics * http://armlinux.simtec.co.uk/ * Ben Dooks * - * S3C Platform - GPIO pin configuration helper definitions + * Samsung Platform - GPIO pin configuration helper definitions * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -24,120 +24,30 @@ * by disabling interrupts. */ -static inline int s3c_gpio_do_setcfg(struct s3c_gpio_chip *chip, - unsigned int off, unsigned int config) +static inline int samsung_gpio_do_setcfg(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int config) { return (chip->config->set_config)(chip, off, config); } -static inline unsigned s3c_gpio_do_getcfg(struct s3c_gpio_chip *chip, - unsigned int off) +static inline unsigned samsung_gpio_do_getcfg(struct samsung_gpio_chip *chip, + unsigned int off) { return (chip->config->get_config)(chip, off); } -static inline int s3c_gpio_do_setpull(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull) +static inline int samsung_gpio_do_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) { return (chip->config->set_pull)(chip, off, pull); } -static inline s3c_gpio_pull_t s3c_gpio_do_getpull(struct s3c_gpio_chip *chip, - unsigned int off) +static inline samsung_gpio_pull_t samsung_gpio_do_getpull(struct samsung_gpio_chip *chip, + unsigned int off) { return chip->config->get_pull(chip, off); } -/** - * s3c_gpio_setcfg_s3c24xx - S3C24XX style GPIO configuration. - * @chip: The gpio chip that is being configured. - * @off: The offset for the GPIO being configured. - * @cfg: The configuration value to set. - * - * This helper deal with the GPIO cases where the control register - * has two bits of configuration per gpio, which have the following - * functions: - * 00 = input - * 01 = output - * 1x = special function -*/ -extern int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip, - unsigned int off, unsigned int cfg); - -/** - * s3c_gpio_getcfg_s3c24xx - S3C24XX style GPIO configuration read. - * @chip: The gpio chip that is being configured. - * @off: The offset for the GPIO being configured. - * - * The reverse of s3c_gpio_setcfg_s3c24xx(). Will return a value whicg - * could be directly passed back to s3c_gpio_setcfg_s3c24xx(), from the - * S3C_GPIO_SPECIAL() macro. - */ -unsigned int s3c_gpio_getcfg_s3c24xx(struct s3c_gpio_chip *chip, - unsigned int off); - -/** - * s3c_gpio_setcfg_s3c24xx_a - S3C24XX style GPIO configuration (Bank A) - * @chip: The gpio chip that is being configured. - * @off: The offset for the GPIO being configured. - * @cfg: The configuration value to set. - * - * This helper deal with the GPIO cases where the control register - * has one bit of configuration for the gpio, where setting the bit - * means the pin is in special function mode and unset means output. -*/ -extern int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip, - unsigned int off, unsigned int cfg); - - -/** - * s3c_gpio_getcfg_s3c24xx_a - S3C24XX style GPIO configuration read (Bank A) - * @chip: The gpio chip that is being configured. - * @off: The offset for the GPIO being configured. - * - * The reverse of s3c_gpio_setcfg_s3c24xx_a() turning an GPIO into a usable - * GPIO configuration value. - * - * @sa s3c_gpio_getcfg_s3c24xx - * @sa s3c_gpio_getcfg_s3c64xx_4bit - */ -extern unsigned s3c_gpio_getcfg_s3c24xx_a(struct s3c_gpio_chip *chip, - unsigned int off); - -/** - * s3c_gpio_setcfg_s3c64xx_4bit - S3C64XX 4bit single register GPIO config. - * @chip: The gpio chip that is being configured. - * @off: The offset for the GPIO being configured. - * @cfg: The configuration value to set. - * - * This helper deal with the GPIO cases where the control register has 4 bits - * of control per GPIO, generally in the form of: - * 0000 = Input - * 0001 = Output - * others = Special functions (dependent on bank) - * - * Note, since the code to deal with the case where there are two control - * registers instead of one, we do not have a separate set of functions for - * each case. -*/ -extern int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip, - unsigned int off, unsigned int cfg); - - -/** - * s3c_gpio_getcfg_s3c64xx_4bit - S3C64XX 4bit single register GPIO config read. - * @chip: The gpio chip that is being configured. - * @off: The offset for the GPIO being configured. - * - * The reverse of s3c_gpio_setcfg_s3c64xx_4bit(), turning a gpio configuration - * register setting into a value the software can use, such as could be passed - * to s3c_gpio_setcfg_s3c64xx_4bit(). - * - * @sa s3c_gpio_getcfg_s3c24xx - */ -extern unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip, - unsigned int off); - /* Pull-{up,down} resistor controls. * * S3C2410,S3C2440 = Pull-UP, @@ -147,7 +57,7 @@ extern unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip, */ /** - * s3c_gpio_setpull_1up() - Pull configuration for choice of up or none. + * s3c24xx_gpio_setpull_1up() - Pull configuration for choice of up or none. * @chip: The gpio chip that is being configured. * @off: The offset for the GPIO being configured. * @param: pull: The pull mode being requested. @@ -155,11 +65,11 @@ extern unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip, * This is a helper function for the case where we have GPIOs with one * bit configuring the presence of a pull-up resistor. */ -extern int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull); +extern int s3c24xx_gpio_setpull_1up(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); /** - * s3c_gpio_setpull_1down() - Pull configuration for choice of down or none + * s3c24xx_gpio_setpull_1down() - Pull configuration for choice of down or none * @chip: The gpio chip that is being configured * @off: The offset for the GPIO being configured * @param: pull: The pull mode being requested @@ -167,11 +77,13 @@ extern int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip, * This is a helper function for the case where we have GPIOs with one * bit configuring the presence of a pull-down resistor. */ -extern int s3c_gpio_setpull_1down(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull); +extern int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); /** - * s3c_gpio_setpull_upown() - Pull configuration for choice of up, down or none + * samsung_gpio_setpull_upown() - Pull configuration for choice of up, + * down or none + * * @chip: The gpio chip that is being configured. * @off: The offset for the GPIO being configured. * @param: pull: The pull mode being requested. @@ -183,45 +95,46 @@ extern int s3c_gpio_setpull_1down(struct s3c_gpio_chip *chip, * 01 = Pull-up resistor connected * 10 = Pull-down resistor connected */ -extern int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull); - +extern int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); /** - * s3c_gpio_getpull_updown() - Get configuration for choice of up, down or none + * samsung_gpio_getpull_updown() - Get configuration for choice of up, + * down or none + * * @chip: The gpio chip that the GPIO pin belongs to * @off: The offset to the pin to get the configuration of. * - * This helper function reads the state of the pull-{up,down} resistor for the - * given GPIO in the same case as s3c_gpio_setpull_upown. + * This helper function reads the state of the pull-{up,down} resistor + * for the given GPIO in the same case as samsung_gpio_setpull_upown. */ -extern s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip, - unsigned int off); +extern samsung_gpio_pull_t samsung_gpio_getpull_updown(struct samsung_gpio_chip *chip, + unsigned int off); /** - * s3c_gpio_getpull_1up() - Get configuration for choice of up or none + * s3c24xx_gpio_getpull_1up() - Get configuration for choice of up or none * @chip: The gpio chip that the GPIO pin belongs to * @off: The offset to the pin to get the configuration of. * * This helper function reads the state of the pull-up resistor for the - * given GPIO in the same case as s3c_gpio_setpull_1up. + * given GPIO in the same case as s3c24xx_gpio_setpull_1up. */ -extern s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip, - unsigned int off); +extern samsung_gpio_pull_t s3c24xx_gpio_getpull_1up(struct samsung_gpio_chip *chip, + unsigned int off); /** - * s3c_gpio_getpull_1down() - Get configuration for choice of down or none + * s3c24xx_gpio_getpull_1down() - Get configuration for choice of down or none * @chip: The gpio chip that the GPIO pin belongs to * @off: The offset to the pin to get the configuration of. * * This helper function reads the state of the pull-down resistor for the - * given GPIO in the same case as s3c_gpio_setpull_1down. + * given GPIO in the same case as s3c24xx_gpio_setpull_1down. */ -extern s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip, - unsigned int off); +extern samsung_gpio_pull_t s3c24xx_gpio_getpull_1down(struct samsung_gpio_chip *chip, + unsigned int off); /** - * s3c_gpio_setpull_s3c2443() - Pull configuration for s3c2443. + * s3c2443_gpio_setpull() - Pull configuration for s3c2443. * @chip: The gpio chip that is being configured. * @off: The offset for the GPIO being configured. * @param: pull: The pull mode being requested. @@ -233,19 +146,18 @@ extern s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip, * 10 = Pull-down resistor connected * x1 = No pull up resistor */ -extern int s3c_gpio_setpull_s3c2443(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull); +extern int s3c2443_gpio_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); /** - * s3c_gpio_getpull_s3c2443() - Get configuration for s3c2443 pull resistors + * s3c2443_gpio_getpull() - Get configuration for s3c2443 pull resistors * @chip: The gpio chip that the GPIO pin belongs to. * @off: The offset to the pin to get the configuration of. * * This helper function reads the state of the pull-{up,down} resistor for the - * given GPIO in the same case as s3c_gpio_setpull_upown. + * given GPIO in the same case as samsung_gpio_setpull_upown. */ -extern s3c_gpio_pull_t s3c_gpio_getpull_s3c2443(struct s3c_gpio_chip *chip, +extern samsung_gpio_pull_t s3c2443_gpio_getpull(struct samsung_gpio_chip *chip, unsigned int off); #endif /* __PLAT_GPIO_CFG_HELPERS_H */ - diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h index 1762dcb4cb9e..d48245bb02b3 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h @@ -24,14 +24,14 @@ #ifndef __PLAT_GPIO_CFG_H #define __PLAT_GPIO_CFG_H __FILE__ -typedef unsigned int __bitwise__ s3c_gpio_pull_t; +typedef unsigned int __bitwise__ samsung_gpio_pull_t; typedef unsigned int __bitwise__ s5p_gpio_drvstr_t; /* forward declaration if gpio-core.h hasn't been included */ -struct s3c_gpio_chip; +struct samsung_gpio_chip; /** - * struct s3c_gpio_cfg GPIO configuration + * struct samsung_gpio_cfg GPIO configuration * @cfg_eint: Configuration setting when used for external interrupt source * @get_pull: Read the current pull configuration for the GPIO * @set_pull: Set the current pull configuraiton for the GPIO @@ -44,20 +44,20 @@ struct s3c_gpio_chip; * per-bank configuration information that other systems such as the * external interrupt code will need. * - * @sa s3c_gpio_cfgpin + * @sa samsung_gpio_cfgpin * @sa s3c_gpio_getcfg * @sa s3c_gpio_setpull * @sa s3c_gpio_getpull */ -struct s3c_gpio_cfg { +struct samsung_gpio_cfg { unsigned int cfg_eint; - s3c_gpio_pull_t (*get_pull)(struct s3c_gpio_chip *chip, unsigned offs); - int (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs, - s3c_gpio_pull_t pull); + samsung_gpio_pull_t (*get_pull)(struct samsung_gpio_chip *chip, unsigned offs); + int (*set_pull)(struct samsung_gpio_chip *chip, unsigned offs, + samsung_gpio_pull_t pull); - unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs); - int (*set_config)(struct s3c_gpio_chip *chip, unsigned offs, + unsigned (*get_config)(struct samsung_gpio_chip *chip, unsigned offs); + int (*set_config)(struct samsung_gpio_chip *chip, unsigned offs, unsigned config); }; @@ -69,7 +69,7 @@ struct s3c_gpio_cfg { #define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1)) #define S3C_GPIO_SFN(x) (S3C_GPIO_SPECIAL(x)) -#define s3c_gpio_is_cfg_special(_cfg) \ +#define samsung_gpio_is_cfg_special(_cfg) \ (((_cfg) & S3C_GPIO_SPECIAL_MARK) == S3C_GPIO_SPECIAL_MARK) /** @@ -128,9 +128,9 @@ extern int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, * up or down settings, and it may be dependent on the chip that is being * used to whether the particular mode is available. */ -#define S3C_GPIO_PULL_NONE ((__force s3c_gpio_pull_t)0x00) -#define S3C_GPIO_PULL_DOWN ((__force s3c_gpio_pull_t)0x01) -#define S3C_GPIO_PULL_UP ((__force s3c_gpio_pull_t)0x02) +#define S3C_GPIO_PULL_NONE ((__force samsung_gpio_pull_t)0x00) +#define S3C_GPIO_PULL_DOWN ((__force samsung_gpio_pull_t)0x01) +#define S3C_GPIO_PULL_UP ((__force samsung_gpio_pull_t)0x02) /** * s3c_gpio_setpull() - set the state of a gpio pin pull resistor @@ -143,7 +143,7 @@ extern int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, * * @pull is one of S3C_GPIO_PULL_NONE, S3C_GPIO_PULL_DOWN or S3C_GPIO_PULL_UP. */ -extern int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull); +extern int s3c_gpio_setpull(unsigned int pin, samsung_gpio_pull_t pull); /** * s3c_gpio_getpull() - get the pull resistor state of a gpio pin @@ -151,7 +151,7 @@ extern int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull); * * Read the pull resistor value for the specified pin. */ -extern s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin); +extern samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin); /* configure `all` aspects of an gpio */ @@ -170,7 +170,7 @@ extern s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin); * @sa s3c_gpio_cfgpin_range */ extern int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, - unsigned int cfg, s3c_gpio_pull_t pull); + unsigned int cfg, samsung_gpio_pull_t pull); static inline int s3c_gpio_cfgrange_nopull(unsigned int pin, unsigned int size, unsigned int cfg) diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h index 8cad4cf19c3c..1fe6917f6a2a 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-core.h +++ b/arch/arm/plat-samsung/include/plat/gpio-core.h @@ -25,22 +25,22 @@ * specific code. */ -struct s3c_gpio_chip; +struct samsung_gpio_chip; /** - * struct s3c_gpio_pm - power management (suspend/resume) information + * struct samsung_gpio_pm - power management (suspend/resume) information * @save: Routine to save the state of the GPIO block * @resume: Routine to resume the GPIO block. */ -struct s3c_gpio_pm { - void (*save)(struct s3c_gpio_chip *chip); - void (*resume)(struct s3c_gpio_chip *chip); +struct samsung_gpio_pm { + void (*save)(struct samsung_gpio_chip *chip); + void (*resume)(struct samsung_gpio_chip *chip); }; -struct s3c_gpio_cfg; +struct samsung_gpio_cfg; /** - * struct s3c_gpio_chip - wrapper for specific implementation of gpio + * struct samsung_gpio_chip - wrapper for specific implementation of gpio * @chip: The chip structure to be exported via gpiolib. * @base: The base pointer to the gpio configuration registers. * @group: The group register number for gpio interrupt support. @@ -60,10 +60,10 @@ struct s3c_gpio_cfg; * CPU cores trying to get one lock for different GPIO banks, where each * bank of GPIO has its own register space and configuration registers. */ -struct s3c_gpio_chip { +struct samsung_gpio_chip { struct gpio_chip chip; - struct s3c_gpio_cfg *config; - struct s3c_gpio_pm *pm; + struct samsung_gpio_cfg *config; + struct samsung_gpio_pm *pm; void __iomem *base; int irq_base; int group; @@ -73,58 +73,11 @@ struct s3c_gpio_chip { #endif }; -static inline struct s3c_gpio_chip *to_s3c_gpio(struct gpio_chip *gpc) +static inline struct samsung_gpio_chip *to_samsung_gpio(struct gpio_chip *gpc) { - return container_of(gpc, struct s3c_gpio_chip, chip); + return container_of(gpc, struct samsung_gpio_chip, chip); } -/** s3c_gpiolib_add() - add the s3c specific version of a gpio_chip. - * @chip: The chip to register - * - * This is a wrapper to gpiochip_add() that takes our specific gpio chip - * information and makes the necessary alterations for the platform and - * notes the information for use with the configuration systems and any - * other parts of the system. - */ -extern void s3c_gpiolib_add(struct s3c_gpio_chip *chip); - -/* CONFIG_S3C_GPIO_TRACK enables the tracking of the s3c specific gpios - * for use with the configuration calls, and other parts of the s3c gpiolib - * support code. - * - * Not all s3c support code will need this, as some configurations of cpu - * may only support one or two different configuration options and have an - * easy gpio to s3c_gpio_chip mapping function. If this is the case, then - * the machine support file should provide its own s3c_gpiolib_getchip() - * and any other necessary functions. - */ - -/** - * samsung_gpiolib_add_4bit_chips - 4bit single register GPIO config. - * @chip: The gpio chip that is being configured. - * @nr_chips: The no of chips (gpio ports) for the GPIO being configured. - * - * This helper deal with the GPIO cases where the control register has 4 bits - * of control per GPIO, generally in the form of: - * 0000 = Input - * 0001 = Output - * others = Special functions (dependent on bank) - * - * Note, since the code to deal with the case where there are two control - * registers instead of one, we do not have a separate set of function - * (samsung_gpiolib_add_4bit2_chips)for each case. - */ -extern void samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip, - int nr_chips); -extern void samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip, - int nr_chips); -extern void samsung_gpiolib_add_2bit_chips(struct s3c_gpio_chip *chip, - int nr_chips); - -extern void samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip); -extern void samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip); - - /** * samsung_gpiolib_to_irq - convert gpio pin to irq number * @chip: The gpio chip that the pin belongs to. @@ -136,36 +89,36 @@ extern void samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip); extern int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset); /* exported for core SoC support to change */ -extern struct s3c_gpio_cfg s3c24xx_gpiocfg_default; +extern struct samsung_gpio_cfg s3c24xx_gpiocfg_default; #ifdef CONFIG_S3C_GPIO_TRACK -extern struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END]; +extern struct samsung_gpio_chip *s3c_gpios[S3C_GPIO_END]; -static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int chip) +static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int chip) { return (chip < S3C_GPIO_END) ? s3c_gpios[chip] : NULL; } #else -/* machine specific code should provide s3c_gpiolib_getchip */ +/* machine specific code should provide samsung_gpiolib_getchip */ #include -static inline void s3c_gpiolib_track(struct s3c_gpio_chip *chip) { } +static inline void s3c_gpiolib_track(struct samsung_gpio_chip *chip) { } #endif #ifdef CONFIG_PM -extern struct s3c_gpio_pm s3c_gpio_pm_1bit; -extern struct s3c_gpio_pm s3c_gpio_pm_2bit; -extern struct s3c_gpio_pm s3c_gpio_pm_4bit; +extern struct samsung_gpio_pm samsung_gpio_pm_1bit; +extern struct samsung_gpio_pm samsung_gpio_pm_2bit; +extern struct samsung_gpio_pm samsung_gpio_pm_4bit; #define __gpio_pm(x) x #else -#define s3c_gpio_pm_1bit NULL -#define s3c_gpio_pm_2bit NULL -#define s3c_gpio_pm_4bit NULL +#define samsung_gpio_pm_1bit NULL +#define samsung_gpio_pm_2bit NULL +#define samsung_gpio_pm_4bit NULL #define __gpio_pm(x) NULL #endif /* CONFIG_PM */ /* locking wrappers to deal with multiple access to the same gpio bank */ -#define s3c_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl) -#define s3c_gpio_unlock(_oc, _fl) spin_unlock_irqrestore(&(_oc)->lock, _fl) +#define samsung_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl) +#define samsung_gpio_unlock(_oc, _fl) spin_unlock_irqrestore(&(_oc)->lock, _fl) diff --git a/arch/arm/plat-samsung/include/plat/gpio-fns.h b/arch/arm/plat-samsung/include/plat/gpio-fns.h new file mode 100644 index 000000000000..bab139201761 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/gpio-fns.h @@ -0,0 +1,98 @@ +/* arch/arm/mach-s3c2410/include/mach/gpio-fns.h + * + * Copyright (c) 2003-2009 Simtec Electronics + * Ben Dooks + * + * S3C2410 - hardware + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __MACH_GPIO_FNS_H +#define __MACH_GPIO_FNS_H __FILE__ + +/* These functions are in the to-be-removed category and it is strongly + * encouraged not to use these in new code. They will be marked deprecated + * very soon. + * + * Most of the functionality can be either replaced by the gpiocfg calls + * for the s3c platform or by the generic GPIOlib API. + * + * As of 2.6.35-rc, these will be removed, with the few drivers using them + * either replaced or given a wrapper until the calls can be removed. +*/ + +#include + +static inline void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int cfg) +{ + /* 1:1 mapping between cfgpin and setcfg calls at the moment */ + s3c_gpio_cfgpin(pin, cfg); +} + +/* external functions for GPIO support + * + * These allow various different clients to access the same GPIO + * registers without conflicting. If your driver only owns the entire + * GPIO register, then it is safe to ioremap/__raw_{read|write} to it. +*/ + +extern unsigned int s3c2410_gpio_getcfg(unsigned int pin); + +/* s3c2410_gpio_getirq + * + * turn the given pin number into the corresponding IRQ number + * + * returns: + * < 0 = no interrupt for this pin + * >=0 = interrupt number for the pin +*/ + +extern int s3c2410_gpio_getirq(unsigned int pin); + +/* s3c2410_gpio_irqfilter + * + * set the irq filtering on the given pin + * + * on = 0 => disable filtering + * 1 => enable filtering + * + * config = S3C2410_EINTFLT_PCLK or S3C2410_EINTFLT_EXTCLK orred with + * width of filter (0 through 63) + * + * +*/ + +extern int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, + unsigned int config); + +/* s3c2410_gpio_pullup + * + * This call should be replaced with s3c_gpio_setpull(). + * + * As a note, there is currently no distinction between pull-up and pull-down + * in the s3c24xx series devices with only an on/off configuration. + */ + +/* s3c2410_gpio_pullup + * + * configure the pull-up control on the given pin + * + * to = 1 => disable the pull-up + * 0 => enable the pull-up + * + * eg; + * + * s3c2410_gpio_pullup(S3C2410_GPB(0), 0); + * s3c2410_gpio_pullup(S3C2410_GPE(8), 0); +*/ + +extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to); + +extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to); + +extern unsigned int s3c2410_gpio_getpin(unsigned int pin); + +#endif /* __MACH_GPIO_FNS_H */ diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index f6749916d194..dcf68709f9cf 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -165,20 +165,20 @@ extern void s3c_pm_check_store(void); extern void s3c_pm_configure_extint(void); /** - * s3c_pm_restore_gpios() - restore the state of the gpios after sleep. + * samsung_pm_restore_gpios() - restore the state of the gpios after sleep. * * Restore the state of the GPIO pins after sleep, which may involve ensuring * that we do not glitch the state of the pins from that the bootloader's * resume code has done. */ -extern void s3c_pm_restore_gpios(void); +extern void samsung_pm_restore_gpios(void); /** - * s3c_pm_save_gpios() - save the state of the GPIOs for restoring after sleep. + * samsung_pm_save_gpios() - save the state of the GPIOs for restoring after sleep. * - * Save the GPIO states for resotration on resume. See s3c_pm_restore_gpios(). + * Save the GPIO states for resotration on resume. See samsung_pm_restore_gpios(). */ -extern void s3c_pm_save_gpios(void); +extern void samsung_pm_save_gpios(void); extern void s3c_pm_save_core(void); extern void s3c_pm_restore_core(void); diff --git a/arch/arm/plat-samsung/pm-gpio.c b/arch/arm/plat-samsung/pm-gpio.c index 96528200eb79..4be016eaa6db 100644 --- a/arch/arm/plat-samsung/pm-gpio.c +++ b/arch/arm/plat-samsung/pm-gpio.c @@ -28,13 +28,13 @@ #define OFFS_DAT (0x04) #define OFFS_UP (0x08) -static void s3c_gpio_pm_1bit_save(struct s3c_gpio_chip *chip) +static void samsung_gpio_pm_1bit_save(struct samsung_gpio_chip *chip) { chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON); chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT); } -static void s3c_gpio_pm_1bit_resume(struct s3c_gpio_chip *chip) +static void samsung_gpio_pm_1bit_resume(struct samsung_gpio_chip *chip) { void __iomem *base = chip->base; u32 old_gpcon = __raw_readl(base + OFFS_CON); @@ -60,12 +60,12 @@ static void s3c_gpio_pm_1bit_resume(struct s3c_gpio_chip *chip) chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); } -struct s3c_gpio_pm s3c_gpio_pm_1bit = { - .save = s3c_gpio_pm_1bit_save, - .resume = s3c_gpio_pm_1bit_resume, +struct samsung_gpio_pm samsung_gpio_pm_1bit = { + .save = samsung_gpio_pm_1bit_save, + .resume = samsung_gpio_pm_1bit_resume, }; -static void s3c_gpio_pm_2bit_save(struct s3c_gpio_chip *chip) +static void samsung_gpio_pm_2bit_save(struct samsung_gpio_chip *chip) { chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON); chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT); @@ -95,7 +95,7 @@ static inline int is_out(unsigned long con) } /** - * s3c_gpio_pm_2bit_resume() - restore the given GPIO bank + * samsung_gpio_pm_2bit_resume() - restore the given GPIO bank * @chip: The chip information to resume. * * Restore one of the GPIO banks that was saved during suspend. This is @@ -121,7 +121,7 @@ static inline int is_out(unsigned long con) * [1] this assumes that writing to a pin DAT whilst in SFN will set the * state for when it is next output. */ -static void s3c_gpio_pm_2bit_resume(struct s3c_gpio_chip *chip) +static void samsung_gpio_pm_2bit_resume(struct samsung_gpio_chip *chip) { void __iomem *base = chip->base; u32 old_gpcon = __raw_readl(base + OFFS_CON); @@ -187,13 +187,13 @@ static void s3c_gpio_pm_2bit_resume(struct s3c_gpio_chip *chip) chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); } -struct s3c_gpio_pm s3c_gpio_pm_2bit = { - .save = s3c_gpio_pm_2bit_save, - .resume = s3c_gpio_pm_2bit_resume, +struct samsung_gpio_pm samsung_gpio_pm_2bit = { + .save = samsung_gpio_pm_2bit_save, + .resume = samsung_gpio_pm_2bit_resume, }; #if defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_PLAT_S5P) -static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip) +static void samsung_gpio_pm_4bit_save(struct samsung_gpio_chip *chip) { chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON); chip->pm_save[2] = __raw_readl(chip->base + OFFS_DAT); @@ -203,7 +203,7 @@ static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip) chip->pm_save[0] = __raw_readl(chip->base - 4); } -static u32 s3c_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon) +static u32 samsung_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon) { u32 old, new, mask; u32 change_mask = 0x0; @@ -242,14 +242,14 @@ static u32 s3c_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon) return change_mask; } -static void s3c_gpio_pm_4bit_con(struct s3c_gpio_chip *chip, int index) +static void samsung_gpio_pm_4bit_con(struct samsung_gpio_chip *chip, int index) { void __iomem *con = chip->base + (index * 4); u32 old_gpcon = __raw_readl(con); u32 gps_gpcon = chip->pm_save[index + 1]; u32 gpcon, mask; - mask = s3c_gpio_pm_4bit_mask(old_gpcon, gps_gpcon); + mask = samsung_gpio_pm_4bit_mask(old_gpcon, gps_gpcon); gpcon = old_gpcon & ~mask; gpcon |= gps_gpcon & mask; @@ -257,7 +257,7 @@ static void s3c_gpio_pm_4bit_con(struct s3c_gpio_chip *chip, int index) __raw_writel(gpcon, con); } -static void s3c_gpio_pm_4bit_resume(struct s3c_gpio_chip *chip) +static void samsung_gpio_pm_4bit_resume(struct samsung_gpio_chip *chip) { void __iomem *base = chip->base; u32 old_gpcon[2]; @@ -269,10 +269,10 @@ static void s3c_gpio_pm_4bit_resume(struct s3c_gpio_chip *chip) old_gpcon[0] = 0; old_gpcon[1] = __raw_readl(base + OFFS_CON); - s3c_gpio_pm_4bit_con(chip, 0); + samsung_gpio_pm_4bit_con(chip, 0); if (chip->chip.ngpio > 8) { old_gpcon[0] = __raw_readl(base - 4); - s3c_gpio_pm_4bit_con(chip, -1); + samsung_gpio_pm_4bit_con(chip, -1); } /* Now change the configurations that require DAT,CON */ @@ -298,19 +298,19 @@ static void s3c_gpio_pm_4bit_resume(struct s3c_gpio_chip *chip) old_gpdat, gps_gpdat); } -struct s3c_gpio_pm s3c_gpio_pm_4bit = { - .save = s3c_gpio_pm_4bit_save, - .resume = s3c_gpio_pm_4bit_resume, +struct samsung_gpio_pm samsung_gpio_pm_4bit = { + .save = samsung_gpio_pm_4bit_save, + .resume = samsung_gpio_pm_4bit_resume, }; #endif /* CONFIG_ARCH_S3C64XX || CONFIG_PLAT_S5P */ /** - * s3c_pm_save_gpio() - save gpio chip data for suspend + * samsung_pm_save_gpio() - save gpio chip data for suspend * @ourchip: The chip for suspend. */ -static void s3c_pm_save_gpio(struct s3c_gpio_chip *ourchip) +static void samsung_pm_save_gpio(struct samsung_gpio_chip *ourchip) { - struct s3c_gpio_pm *pm = ourchip->pm; + struct samsung_gpio_pm *pm = ourchip->pm; if (pm == NULL || pm->save == NULL) S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label); @@ -319,24 +319,24 @@ static void s3c_pm_save_gpio(struct s3c_gpio_chip *ourchip) } /** - * s3c_pm_save_gpios() - Save the state of the GPIO banks. + * samsung_pm_save_gpios() - Save the state of the GPIO banks. * * For all the GPIO banks, save the state of each one ready for going * into a suspend mode. */ -void s3c_pm_save_gpios(void) +void samsung_pm_save_gpios(void) { - struct s3c_gpio_chip *ourchip; + struct samsung_gpio_chip *ourchip; unsigned int gpio_nr; for (gpio_nr = 0; gpio_nr < S3C_GPIO_END;) { - ourchip = s3c_gpiolib_getchip(gpio_nr); + ourchip = samsung_gpiolib_getchip(gpio_nr); if (!ourchip) { gpio_nr++; continue; } - s3c_pm_save_gpio(ourchip); + samsung_pm_save_gpio(ourchip); S3C_PMDBG("%s: save %08x,%08x,%08x,%08x\n", ourchip->chip.label, @@ -351,12 +351,12 @@ void s3c_pm_save_gpios(void) } /** - * s3c_pm_resume_gpio() - restore gpio chip data after suspend + * samsung_pm_resume_gpio() - restore gpio chip data after suspend * @ourchip: The suspended chip. */ -static void s3c_pm_resume_gpio(struct s3c_gpio_chip *ourchip) +static void samsung_pm_resume_gpio(struct samsung_gpio_chip *ourchip) { - struct s3c_gpio_pm *pm = ourchip->pm; + struct samsung_gpio_pm *pm = ourchip->pm; if (pm == NULL || pm->resume == NULL) S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label); @@ -364,19 +364,19 @@ static void s3c_pm_resume_gpio(struct s3c_gpio_chip *ourchip) pm->resume(ourchip); } -void s3c_pm_restore_gpios(void) +void samsung_pm_restore_gpios(void) { - struct s3c_gpio_chip *ourchip; + struct samsung_gpio_chip *ourchip; unsigned int gpio_nr; for (gpio_nr = 0; gpio_nr < S3C_GPIO_END;) { - ourchip = s3c_gpiolib_getchip(gpio_nr); + ourchip = samsung_gpiolib_getchip(gpio_nr); if (!ourchip) { gpio_nr++; continue; } - s3c_pm_resume_gpio(ourchip); + samsung_pm_resume_gpio(ourchip); gpio_nr += ourchip->chip.ngpio; gpio_nr += CONFIG_S3C_GPIO_SPACE; diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index ae6f99834cdd..64ab65f0fdbc 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -268,8 +268,8 @@ static int s3c_pm_enter(suspend_state_t state) /* save all necessary core registers not covered by the drivers */ - s3c_pm_save_gpios(); - s3c_pm_saved_gpios(); + samsung_pm_save_gpios(); + samsung_pm_saved_gpios(); s3c_pm_save_uarts(); s3c_pm_save_core(); @@ -306,7 +306,7 @@ static int s3c_pm_enter(suspend_state_t state) s3c_pm_restore_core(); s3c_pm_restore_uarts(); - s3c_pm_restore_gpios(); + samsung_pm_restore_gpios(); s3c_pm_restored_gpios(); s3c_pm_debug_init(); From 5ec7414494ed1204c9e2ed0b8232b29860d0986f Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Tue, 30 Aug 2011 20:35:05 +0900 Subject: [PATCH 0440/1596] ARM: SAMSUNG: Remove useless Samsung GPIO related CONFIGs Cc: Ben Dooks Signed-off-by: Kukjin Kim --- arch/arm/Kconfig | 3 --- arch/arm/mach-s3c2410/Kconfig | 1 - arch/arm/mach-s3c2416/Kconfig | 1 - arch/arm/mach-s3c2440/Kconfig | 2 -- arch/arm/mach-s3c2443/Kconfig | 1 - arch/arm/plat-s3c24xx/Kconfig | 1 - arch/arm/plat-s5p/Kconfig | 3 --- arch/arm/plat-samsung/Kconfig | 27 --------------------------- 8 files changed, 39 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3269576dbfa8..42401daa165f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -724,9 +724,6 @@ config ARCH_S3C64XX select SAMSUNG_IRQ_VIC_TIMER select SAMSUNG_IRQ_UART select S3C_GPIO_TRACK - select S3C_GPIO_PULL_UPDOWN - select S3C_GPIO_CFG_S3C24XX - select S3C_GPIO_CFG_S3C64XX select S3C_DEV_NAND select USB_ARCH_HAS_OHCI select SAMSUNG_GPIOLIB_4BIT diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 3700cf32af0f..5261a7ed0999 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -6,7 +6,6 @@ config CPU_S3C2410 bool depends on ARCH_S3C2410 select CPU_ARM920T - select S3C_GPIO_PULL_UP select S3C2410_CLOCK select CPU_LLSERIAL_S3C2410 select S3C2410_PM if PM diff --git a/arch/arm/mach-s3c2416/Kconfig b/arch/arm/mach-s3c2416/Kconfig index 69b48a7d1dbd..84c7b03e5a30 100644 --- a/arch/arm/mach-s3c2416/Kconfig +++ b/arch/arm/mach-s3c2416/Kconfig @@ -13,7 +13,6 @@ config CPU_S3C2416 select CPU_ARM926T select S3C2416_DMA if S3C2410_DMA select CPU_LLSERIAL_S3C2440 - select S3C_GPIO_PULL_UPDOWN select SAMSUNG_CLKSRC select S3C2443_CLOCK help diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig index c461fb8e15c0..914e620f1257 100644 --- a/arch/arm/mach-s3c2440/Kconfig +++ b/arch/arm/mach-s3c2440/Kconfig @@ -5,7 +5,6 @@ config CPU_S3C2440 bool select CPU_ARM920T - select S3C_GPIO_PULL_UP select S3C2410_CLOCK select S3C2410_PM if PM select S3C2440_DMA if S3C2410_DMA @@ -17,7 +16,6 @@ config CPU_S3C2440 config CPU_S3C2442 bool select CPU_ARM920T - select S3C_GPIO_PULL_DOWN select S3C2410_CLOCK select S3C2410_PM if PM select CPU_S3C244X diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig index d8eb86823df7..8814031516ce 100644 --- a/arch/arm/mach-s3c2443/Kconfig +++ b/arch/arm/mach-s3c2443/Kconfig @@ -10,7 +10,6 @@ config CPU_S3C2443 select CPU_LLSERIAL_S3C2440 select SAMSUNG_CLKSRC select S3C2443_CLOCK - select S3C_GPIO_PULL_S3C2443 help Support for the S3C2443 SoC from the S3C24XX line diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig index 8c5b3029b39f..d8973ac46bc4 100644 --- a/arch/arm/plat-s3c24xx/Kconfig +++ b/arch/arm/plat-s3c24xx/Kconfig @@ -9,7 +9,6 @@ config PLAT_S3C24XX select NO_IOPORT select ARCH_REQUIRE_GPIOLIB select S3C_DEV_NAND - select S3C_GPIO_CFG_S3C24XX help Base platform code for any Samsung S3C24XX device diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index 9843c954c042..ac610bee2cb3 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -16,9 +16,6 @@ config PLAT_S5P select S3C_GPIO_TRACK select S5P_GPIO_DRVSTR select SAMSUNG_GPIOLIB_4BIT - select S3C_GPIO_CFG_S3C64XX - select S3C_GPIO_PULL_UPDOWN - select S3C_GPIO_CFG_S3C24XX select PLAT_SAMSUNG select SAMSUNG_CLKSRC select SAMSUNG_IRQ_VIC_TIMER diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index b3e10659e4b8..1f346d22323d 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -79,39 +79,12 @@ config SAMSUNG_GPIOLIB_4BIT configuration. GPIOlib shall be compiled only for S3C64XX and S5P series of processors. -config S3C_GPIO_CFG_S3C24XX - bool - help - Internal configuration to enable S3C24XX style GPIO configuration - functions. - config S3C_GPIO_CFG_S3C64XX bool help Internal configuration to enable S3C64XX style GPIO configuration functions. -config S3C_GPIO_PULL_UPDOWN - bool - help - Internal configuration to enable the correct GPIO pull helper - -config S3C_GPIO_PULL_S3C2443 - bool - select S3C_GPIO_PULL_UPDOWN - help - Internal configuration to enable the correct GPIO pull helper for S3C2443-style GPIO - -config S3C_GPIO_PULL_DOWN - bool - help - Internal configuration to enable the correct GPIO pull helper - -config S3C_GPIO_PULL_UP - bool - help - Internal configuration to enable the correct GPIO pull helper - config S5P_GPIO_DRVSTR bool help From 7387ce773256f446bdd0280b2449b635441f906e Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 20 Sep 2011 18:30:51 -0700 Subject: [PATCH 0441/1596] mtd: define `mtd_is_*()' functions These functions can be used instead of referencing -EUCLEAN and -EBADMSG all over the place. They should help make code a little bit more readable. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/linux/mtd/mtd.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 37d082793f62..4bce1eb952cf 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -348,4 +348,16 @@ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size); void mtd_erase_callback(struct erase_info *instr); +static inline int mtd_is_bitflip(int err) { + return err == -EUCLEAN; +} + +static inline int mtd_is_eccerr(int err) { + return err == -EBADMSG; +} + +static inline int mtd_is_bitflip_or_eccerr(int err) { + return mtd_is_bitflip(err) || mtd_is_eccerr(err); +} + #endif /* __MTD_MTD_H__ */ From d57f40544a41fdfe90fd863b6865138c5a82f1cc Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 20 Sep 2011 18:34:25 -0700 Subject: [PATCH 0442/1596] mtd: utilize `mtd_is_*()' functions Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/inftlcore.c | 4 ++-- drivers/mtd/mtdchar.c | 4 ++-- drivers/mtd/mtdconcat.c | 8 ++++---- drivers/mtd/mtdoops.c | 2 +- drivers/mtd/mtdpart.c | 8 ++++---- drivers/mtd/mtdswap.c | 20 ++++++++++---------- drivers/mtd/nand/diskonchip.c | 2 +- drivers/mtd/nand/nand_bbt.c | 4 ++-- drivers/mtd/nftlcore.c | 4 ++-- drivers/mtd/onenand/onenand_base.c | 10 +++++----- drivers/mtd/sm_ftl.c | 4 ++-- drivers/mtd/tests/mtd_pagetest.c | 28 ++++++++++++++-------------- drivers/mtd/tests/mtd_readtest.c | 2 +- drivers/mtd/tests/mtd_speedtest.c | 8 ++++---- drivers/mtd/tests/mtd_stresstest.c | 2 +- drivers/mtd/tests/mtd_subpagetest.c | 8 ++++---- drivers/mtd/tests/mtd_torturetest.c | 2 +- drivers/mtd/ubi/eba.c | 2 +- drivers/mtd/ubi/io.c | 24 ++++++++++++------------ drivers/mtd/ubi/kapi.c | 2 +- drivers/mtd/ubi/misc.c | 2 +- drivers/mtd/ubi/scan.c | 4 ++-- drivers/mtd/ubi/vtbl.c | 2 +- 23 files changed, 78 insertions(+), 78 deletions(-) diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 652065e47a79..dd034efd1875 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -346,7 +346,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, &retlen, movebuf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, @@ -917,7 +917,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer); /* Handle corrected bit flips gracefully */ - if (ret < 0 && ret != -EUCLEAN) + if (ret < 0 && !mtd_is_bitflip(ret)) return -EIO; } return 0; diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 8feb5fdcd97b..47be6e5cefe4 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -242,7 +242,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t * Userspace software which accesses NAND this way * must be aware of the fact that it deals with NAND */ - if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) { + if (!ret || mtd_is_bitflip_or_eccerr(ret)) { *ppos += retlen; if (copy_to_user(buf, kbuf, retlen)) { kfree(kbuf); @@ -491,7 +491,7 @@ static int mtd_do_readoob(struct file *file, struct mtd_info *mtd, * does not calculate ECC for the OOB area, so do not rely on * this behavior unless you have replaced it with your own. */ - if (ret == -EUCLEAN || ret == -EBADMSG) + if (mtd_is_bitflip_or_eccerr(ret)) return 0; return ret; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index d3fabd144d6c..6df4d4d4eb92 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -95,10 +95,10 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len, /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -279,10 +279,10 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index e3e40f440323..1e2fa6236705 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -258,7 +258,7 @@ static void find_next_position(struct mtdoops_context *cxt) ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE, &retlen, (u_char *) &count[0]); if (retlen != MTDOOPS_HEADER_SIZE || - (ret < 0 && ret != -EUCLEAN)) { + (ret < 0 && !mtd_is_bitflip(ret))) { printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n", page * record_size, retlen, MTDOOPS_HEADER_SIZE, ret); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index cd7785aa1649..a0bd2de4752b 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -73,9 +73,9 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len, res = part->master->read(part->master, from + part->offset, len, retlen, buf); if (unlikely(res)) { - if (res == -EUCLEAN) + if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; - if (res == -EBADMSG) + if (mtd_is_eccerr(res)) mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; } return res; @@ -142,9 +142,9 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, res = part->master->read_oob(part->master, from + part->offset, ops); if (unlikely(res)) { - if (res == -EUCLEAN) + if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected++; - if (res == -EBADMSG) + if (mtd_is_eccerr(res)) mtd->ecc_stats.failed++; } return res; diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 910309f260f8..bd9590c723e4 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -314,7 +314,7 @@ static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from, { int ret = d->mtd->read_oob(d->mtd, from, ops); - if (ret == -EUCLEAN) + if (mtd_is_bitflip(ret)) return ret; if (ret) { @@ -354,7 +354,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) ret = mtdswap_read_oob(d, offset, &ops); - if (ret && ret != -EUCLEAN) + if (ret && !mtd_is_bitflip(ret)) return ret; data = (struct mtdswap_oobdata *)d->oob_buf; @@ -363,7 +363,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) { eb->erase_count = le32_to_cpu(data->count); - if (ret == -EUCLEAN) + if (mtd_is_bitflip(ret)) ret = MTDSWAP_SCANNED_BITFLIP; else { if (le16_to_cpu(data2->magic) == MTDSWAP_MAGIC_DIRTY) @@ -408,7 +408,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, if (ret) { dev_warn(d->dev, "Write OOB failed for block at %08llx " "error %d\n", offset, ret); - if (ret == -EIO || ret == -EBADMSG) + if (ret == -EIO || mtd_is_eccerr(ret)) mtdswap_handle_write_error(d, eb); return ret; } @@ -628,7 +628,7 @@ static int mtdswap_map_free_block(struct mtdswap_dev *d, unsigned int page, TREE_COUNT(d, CLEAN)--; ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_DIRTY); - } while (ret == -EIO || ret == -EBADMSG); + } while (ret == -EIO || mtd_is_eccerr(ret)); if (ret) return ret; @@ -678,7 +678,7 @@ static int mtdswap_write_block(struct mtdswap_dev *d, char *buf, ret = mtdswap_map_free_block(d, page, bp); eb = d->eb_data + (*bp / d->pages_per_eblk); - if (ret == -EIO || ret == -EBADMSG) { + if (ret == -EIO || mtd_is_eccerr(ret)) { d->curr_write = NULL; eb->active_count--; d->revmap[*bp] = PAGE_UNDEF; @@ -690,7 +690,7 @@ static int mtdswap_write_block(struct mtdswap_dev *d, char *buf, writepos = (loff_t)*bp << PAGE_SHIFT; ret = mtd->write(mtd, writepos, PAGE_SIZE, &retlen, buf); - if (ret == -EIO || ret == -EBADMSG) { + if (ret == -EIO || mtd_is_eccerr(ret)) { d->curr_write_pos--; eb->active_count--; d->revmap[*bp] = PAGE_UNDEF; @@ -738,7 +738,7 @@ static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock, retry: ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, d->page_buf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { oldeb = d->eb_data + oldblock / d->pages_per_eblk; oldeb->flags |= EBLOCK_READERR; @@ -1016,7 +1016,7 @@ static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background) if (ret == 0) mtdswap_rb_add(d, eb, MTDSWAP_CLEAN); - else if (ret != -EIO && ret != -EBADMSG) + else if (ret != -EIO && !mtd_is_eccerr(ret)) mtdswap_rb_add(d, eb, MTDSWAP_DIRTY); return 0; @@ -1164,7 +1164,7 @@ static int mtdswap_readsect(struct mtd_blktrans_dev *dev, ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, buf); d->mtd_read_count++; - if (ret == -EUCLEAN) { + if (mtd_is_bitflip(ret)) { eb->flags |= EBLOCK_BITFLIP; mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP); ret = 0; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index de93a989aa54..ae8c60d604c1 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1031,7 +1031,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else WriteDOC(DOC_ECC_DIS, docptr, ECCConf); - if (no_ecc_failures && (ret == -EBADMSG)) { + if (no_ecc_failures && mtd_is_eccerr(ret)) { printk(KERN_ERR "suppressing ECC failure\n"); ret = 0; } diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 7dbfce4a1a5b..584bdcb3c61a 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -400,7 +400,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, ret = scan_read_raw_oob(mtd, buf, offs, readlen); /* Ignore ECC errors when checking for BBM */ - if (ret && ret != -EUCLEAN && ret != -EBADMSG) + if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; for (j = 0; j < len; j++, buf += scanlen) { @@ -430,7 +430,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, */ ret = mtd->read_oob(mtd, offs, &ops); /* Ignore ECC errors when checking for BBM */ - if (ret && ret != -EUCLEAN && ret != -EBADMSG) + if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; if (check_short_pattern(buf, bd)) diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 272e3c03e324..cda77b562ad4 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -425,7 +425,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, movebuf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, movebuf); @@ -773,7 +773,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, size_t retlen; int res = mtd->read(mtd, ptr, 512, &retlen, buffer); - if (res < 0 && res != -EUCLEAN) + if (res < 0 && !mtd_is_bitflip(res)) return -EIO; } return 0; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index a52aa0f6b0c3..a8394730b4b6 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1079,7 +1079,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status) return status; /* check if we failed due to uncorrectable error */ - if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR) + if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR) return status; /* check if address lies in MLC region */ @@ -1159,7 +1159,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, if (unlikely(ret)) ret = onenand_recover_lsb(mtd, from, ret); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; if (ret) break; @@ -1255,7 +1255,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, this->command(mtd, ONENAND_CMD_READ, from, writesize); ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; } } @@ -1315,7 +1315,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, /* Now wait for load */ ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; } @@ -1403,7 +1403,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, if (unlikely(ret)) ret = onenand_recover_lsb(mtd, from, ret); - if (ret && ret != -EBADMSG) { + if (ret && !mtd_is_eccerr(ret)) { printk(KERN_ERR "%s: read failed = 0x%x\n", __func__, ret); break; diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index d927641cb0f5..fddb714e323c 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -281,7 +281,7 @@ static int sm_read_sector(struct sm_ftl *ftl, ret = mtd->read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops); /* Test for unknown errors */ - if (ret != 0 && ret != -EUCLEAN && ret != -EBADMSG) { + if (ret != 0 && !mtd_is_bitflip_or_eccerr(ret)) { dbg("read of block %d at zone %d, failed due to error (%d)", block, zone, ret); goto again; @@ -306,7 +306,7 @@ static int sm_read_sector(struct sm_ftl *ftl, } /* Test ECC*/ - if (ret == -EBADMSG || + if (mtd_is_eccerr(ret) || (ftl->smallpagenand && sm_correct_sector(buffer, oob))) { dbg("read of block %d at zone %d, failed due to ECC error", diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c index 00b937e38c1d..186b14c02307 100644 --- a/drivers/mtd/tests/mtd_pagetest.c +++ b/drivers/mtd/tests/mtd_pagetest.c @@ -128,7 +128,7 @@ static int verify_eraseblock(int ebnum) for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { /* Do a read to set the internal dataRAMs to different data */ err = mtd->read(mtd, addr0, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -136,7 +136,7 @@ static int verify_eraseblock(int ebnum) return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -146,7 +146,7 @@ static int verify_eraseblock(int ebnum) memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -164,7 +164,7 @@ static int verify_eraseblock(int ebnum) unsigned long oldnext = next; /* Do a read to set the internal dataRAMs to different data */ err = mtd->read(mtd, addr0, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -172,7 +172,7 @@ static int verify_eraseblock(int ebnum) return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -182,7 +182,7 @@ static int verify_eraseblock(int ebnum) memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -231,7 +231,7 @@ static int crosstest(void) read = 0; addr = addrn - pgsize - pgsize; err = mtd->read(mtd, addr, pgsize, &read, pp1); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -244,7 +244,7 @@ static int crosstest(void) read = 0; addr = addrn - pgsize - pgsize - pgsize; err = mtd->read(mtd, addr, pgsize, &read, pp1); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -258,7 +258,7 @@ static int crosstest(void) addr = addr0; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp2); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -272,7 +272,7 @@ static int crosstest(void) addr = addrn - pgsize; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp3); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -286,7 +286,7 @@ static int crosstest(void) addr = addr0; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp4); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -345,7 +345,7 @@ static int erasecrosstest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd->read(mtd, addr0, pgsize, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -383,7 +383,7 @@ static int erasecrosstest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd->read(mtd, addr0, pgsize, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -439,7 +439,7 @@ static int erasetest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); err = mtd->read(mtd, addr0, pgsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index 587e1e371c6c..756045345f00 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -75,7 +75,7 @@ static int read_eraseblock_by_page(int ebnum) ops.datbuf = NULL; ops.oobbuf = oobbuf; ret = mtd->read_oob(mtd, addr, &ops); - if ((ret && ret != -EUCLEAN) || + if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != mtd->oobsize) { printk(PRINT_PREF "error: read oob failed at " "%#llx\n", (long long)addr); diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 627d4e2466a3..79d53ee62295 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -216,7 +216,7 @@ static int read_eraseblock(int ebnum) err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != mtd->erasesize) { printk(PRINT_PREF "error: read failed at %#llx\n", addr); @@ -237,7 +237,7 @@ static int read_eraseblock_by_page(int ebnum) for (i = 0; i < pgcnt; i++) { err = mtd->read(mtd, addr, pgsize, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -263,7 +263,7 @@ static int read_eraseblock_by_2pages(int ebnum) for (i = 0; i < n; i++) { err = mtd->read(mtd, addr, sz, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != sz) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -278,7 +278,7 @@ static int read_eraseblock_by_2pages(int ebnum) if (pgcnt % 2) { err = mtd->read(mtd, addr, pgsize, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c index 531625fc9259..3c9008adbe3b 100644 --- a/drivers/mtd/tests/mtd_stresstest.c +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -154,7 +154,7 @@ static int do_read(void) } addr = eb * mtd->erasesize + offs; err = mtd->read(mtd, addr, len, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (unlikely(err || read != len)) { printk(PRINT_PREF "error: read failed at 0x%llx\n", diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c index 334eae53a3db..2b51842d08fa 100644 --- a/drivers/mtd/tests/mtd_subpagetest.c +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -198,7 +198,7 @@ static int verify_eraseblock(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -226,7 +226,7 @@ static int verify_eraseblock(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -264,7 +264,7 @@ static int verify_eraseblock2(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf); if (unlikely(err || read != subpgsize * k)) { - if (err == -EUCLEAN && read == subpgsize * k) { + if (mtd_is_bitflip(err) && read == subpgsize * k) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -298,7 +298,7 @@ static int verify_eraseblock_ff(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c index 5c6c3d248901..25786ce97c8e 100644 --- a/drivers/mtd/tests/mtd_torturetest.c +++ b/drivers/mtd/tests/mtd_torturetest.c @@ -138,7 +138,7 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf) retry: err = mtd->read(mtd, addr, len, &read, check_buf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) printk(PRINT_PREF "single bit flip occurred at EB %d " "MTD reported that it was fixed.\n", ebnum); else if (err) { diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 4be671815014..fb7f19b62d91 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -443,7 +443,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, if (err == UBI_IO_BITFLIPS) { scrub = 1; err = 0; - } else if (err == -EBADMSG) { + } else if (mtd_is_eccerr(err)) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) goto out_unlock; scrub = 1; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 6ba55c235873..f20b6f22f240 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -172,9 +172,9 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, retry: err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); if (err) { - const char *errstr = (err == -EBADMSG) ? " (ECC error)" : ""; + const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : ""; - if (err == -EUCLEAN) { + if (mtd_is_bitflip(err)) { /* * -EUCLEAN is reported if there was a bit-flip which * was corrected, so this is harmless. @@ -205,7 +205,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, * all the requested data. But some buggy drivers might do * this, so we change it to -EIO. */ - if (read != len && err == -EBADMSG) { + if (read != len && mtd_is_eccerr(err)) { ubi_assert(0); err = -EIO; } @@ -469,7 +469,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) out: mutex_unlock(&ubi->buf_mutex); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) { /* * If a bit-flip or data integrity error was detected, the test * has not passed because it happened on a freshly erased @@ -760,7 +760,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, read_err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); if (read_err) { - if (read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) + if (read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) return read_err; /* @@ -776,7 +776,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { - if (read_err == -EBADMSG) + if (mtd_is_eccerr(read_err)) return UBI_IO_BAD_HDR_EBADMSG; /* @@ -1032,12 +1032,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, p = (char *)vid_hdr - ubi->vid_hdr_shift; read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); - if (read_err && read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) + if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) return read_err; magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { - if (read_err == -EBADMSG) + if (mtd_is_eccerr(read_err)) return UBI_IO_BAD_HDR_EBADMSG; if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { @@ -1219,7 +1219,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) return -ENOMEM; err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto exit; crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); @@ -1306,7 +1306,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) p = (char *)vid_hdr - ubi->vid_hdr_shift; err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto exit; crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); @@ -1358,7 +1358,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum, } err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1); - if (err && err != -EUCLEAN) + if (err && !mtd_is_bitflip(err)) goto out_free; for (i = 0; i < len; i++) { @@ -1422,7 +1422,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) } err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); - if (err && err != -EUCLEAN) { + if (err && !mtd_is_bitflip(err)) { ubi_err("error %d while reading %d bytes from PEB %d:%d, " "read %zd bytes", err, len, pnum, offset, read); goto error; diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index d39716e5b204..1a35fc5e3b40 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -410,7 +410,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, return 0; err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); - if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { + if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) { ubi_warn("mark volume %d as corrupted", vol_id); vol->corrupted = 1; } diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index ff2a65c37f69..f6a7d7ac4b98 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -81,7 +81,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1); if (err) { - if (err == -EBADMSG) + if (mtd_is_eccerr(err)) err = 1; break; } diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index a3a198f9b98d..0cb17d936b5a 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -395,7 +395,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, } err = ubi_io_read_data(ubi, buf, pnum, 0, len); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto out_free_buf; data_crc = be32_to_cpu(vid_hdr->data_crc); @@ -793,7 +793,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start, ubi->leb_size); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) { /* * Bit-flips or integrity errors while reading the data area. * It is difficult to say for sure what type of corruption is diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 4b50a3029b84..9ad18da1891d 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -423,7 +423,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, ubi->vtbl_size); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) /* * Scrub the PEB later. Note, -EBADMSG indicates an * uncorrectable ECC error, but we have our own CRC and From 167a8d52509a0f7d6728a79e2588b800e866c147 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 20 Sep 2011 18:35:08 -0700 Subject: [PATCH 0443/1596] mtd: nand: report ECC errors properly when reading BBT Instead of just printing a warning when encountering ECC errors, we should return a proper error status and print a more informative warning. Later, we will handle these error messages in the upper layers of the BBT scan. Note that this patch makes our check for ECC error codes a little bit more restrictive, leaving all unrecognized errors to the generic "else" clause. This shouldn't cause problems and could even be a benefit. This code is based on some findings reported by Matthieu Castet. Reported-by: Matthieu CASTET Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 584bdcb3c61a..0ed8591dbd26 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -178,7 +178,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td) static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, struct nand_bbt_descr *td, int offs) { - int res, i, j, act = 0; + int res, ret = 0, i, j, act = 0; struct nand_chip *this = mtd->priv; size_t retlen, len, totlen; loff_t from; @@ -204,11 +204,18 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, } res = mtd->read(mtd, from, len, &retlen, buf); if (res < 0) { - if (retlen != len) { - pr_info("nand_bbt: error reading bad block table\n"); + if (mtd_is_eccerr(res)) { + pr_info("nand_bbt: ECC error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + return res; + } else if (mtd_is_bitflip(res)) { + pr_info("nand_bbt: corrected error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + ret = res; + } else { + pr_info("nand_bbt: error reading BBT\n"); return res; } - pr_warn("nand_bbt: ECC error while reading bad block table\n"); } /* Analyse data */ @@ -242,7 +249,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, totlen -= len; from += len; } - return 0; + return ret; } /** From 623978de362a5faeb18d8395fa86089650642626 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 20 Sep 2011 18:35:34 -0700 Subject: [PATCH 0444/1596] mtd: nand: scrub BBT on ECC errors Now that `read_bbt()' returns ECC error codes properly, we handle those codes when checking the integrity of our flash-based BBT. The modifications can be described by this new policy: *) On any uncorrected ECC error, we invalidate the corresponding table and retry our version-checking integrity logic. *) On corrected bitflips, we mark both tables for re-writing to flash (a.k.a. scrubbing). Current integrity checks (i.e., comparing version numbers, etc.) should take care of all the cases that result in rescanning the device for bad blocks or falling back to the BBT as found in the mirror descriptor. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 0ed8591dbd26..11185aa6273c 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -882,7 +882,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b */ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) { - int i, chips, writeops, create, chipsel, res; + int i, chips, writeops, create, chipsel, res, res2; struct nand_chip *this = mtd->priv; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; @@ -899,6 +899,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc create = 0; rd = NULL; rd2 = NULL; + res = res2 = 0; /* Per chip or per device? */ chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; /* Mirrored table available? */ @@ -951,11 +952,29 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /* Read back first? */ - if (rd) - read_abs_bbt(mtd, buf, rd, chipsel); + if (rd) { + res = read_abs_bbt(mtd, buf, rd, chipsel); + if (mtd_is_eccerr(res)) { + /* Mark table as invalid */ + rd->pages[i] = -1; + i--; + continue; + } + } /* If they weren't versioned, read both */ - if (rd2) - read_abs_bbt(mtd, buf, rd2, chipsel); + if (rd2) { + res2 = read_abs_bbt(mtd, buf, rd2, chipsel); + if (mtd_is_eccerr(res2)) { + /* Mark table as invalid */ + rd2->pages[i] = -1; + i--; + continue; + } + } + + /* Scrub the flash table(s)? */ + if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) + writeops = 0x03; /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { From dadc17a3e34810ed411a62e6b4cafdf3e5e1d5c8 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 20 Sep 2011 18:35:57 -0700 Subject: [PATCH 0445/1596] mtd: nand: wait to set BBT version Because there are so many cases of checking, writing, and re-writing of the bad block table(s), we might as well wait until the we've settled on a valid, clean copy of the table. This also prevents us from falsely incrementing the table version. For example, we may have the following: Primary table, with version 0x02 Mirror table, with version 0x01 Primary table has uncorrectable ECC errors If we don't have this fix applied, then we will: Choose to read the primary table (higher version) Set mirror table version to 0x02 Read back primary table Invalidate table because of ECC errors Retry readback operation with mirror table, now version 0x02 Mirrored table reads cleanly Writeback BBT to primary table location (with "version 0x02") However, the mirrored table shouldn't have a new version number. Instead, we actually want: Choose to read the primary table (higher version) Read back primary table Invalidate table because of ECC errors Retry readback with mirror table (version 0x01) Mirrored table reads cleanly Set both tables to version 0x01 Writeback BBT to primary table location (version 0x01) Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 11185aa6273c..e7976c7a7bb0 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -909,11 +909,9 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc writeops = 0x03; } else if (td->pages[i] == -1) { rd = md; - td->version[i] = md->version[i]; writeops = 0x01; } else if (md->pages[i] == -1) { rd = td; - md->version[i] = td->version[i]; writeops = 0x02; } else if (td->version[i] == md->version[i]) { rd = td; @@ -921,11 +919,9 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc rd2 = md; } else if (((int8_t)(td->version[i] - md->version[i])) > 0) { rd = td; - md->version[i] = td->version[i]; writeops = 0x02; } else { rd = md; - td->version[i] = md->version[i]; writeops = 0x01; } } else { @@ -957,6 +953,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (mtd_is_eccerr(res)) { /* Mark table as invalid */ rd->pages[i] = -1; + rd->version[i] = 0; i--; continue; } @@ -967,6 +964,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (mtd_is_eccerr(res2)) { /* Mark table as invalid */ rd2->pages[i] = -1; + rd2->version[i] = 0; i--; continue; } @@ -976,6 +974,12 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) writeops = 0x03; + /* Update version numbers before writing */ + if (md) { + td->version[i] = max(td->version[i], md->version[i]); + md->version[i] = td->version[i]; + } + /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, td, md, chipsel); From 752ed6c5f8c0ee182219ff8682f5a98e47ee866f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 20 Sep 2011 18:36:42 -0700 Subject: [PATCH 0446/1596] mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set Updates to our default function for creating bad block patterns have broken the "no OOB" feature. The NAND_BBT_NO_OOB option should not be set while scanning for bad blocks, but we've been passing all BBT options from nand_chip.bbt_options to the bad block scan. This causes us to hit the: BUG_ON(bd->options & NAND_BBT_NO_OOB); in create_bbt() when we scan the flash for bad blocks. Thus, while it can be legal to set NAND_BBT_NO_OOB in a custom badblock pattern descriptor (presumably with NAND_BBT_CREATE disabled?), we should not pass it through in our default function. Also, to help clarify and emphasize that the function creates bad block patterns only (not, for example, table descriptors for locating flash-based BBT), I renamed `nand_create_default_bbt_descr' to `nand_create_badblock_pattern'. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index e7976c7a7bb0..783093d1a2e5 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1294,26 +1294,27 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { .pattern = mirror_pattern }; +#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) /** - * nand_create_default_bbt_descr - [INTERN] Creates a BBT descriptor structure + * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure * @this: NAND chip to create descriptor for * * This function allocates and initializes a nand_bbt_descr for BBM detection - * based on the properties of "this". The new descriptor is stored in + * based on the properties of @this. The new descriptor is stored in * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when * passed to this function. */ -static int nand_create_default_bbt_descr(struct nand_chip *this) +static int nand_create_badblock_pattern(struct nand_chip *this) { struct nand_bbt_descr *bd; if (this->badblock_pattern) { - pr_warn("BBT descr already allocated; not replacing\n"); + pr_warn("Bad block pattern already allocated; not replacing\n"); return -EINVAL; } bd = kzalloc(sizeof(*bd), GFP_KERNEL); if (!bd) return -ENOMEM; - bd->options = this->bbt_options; + bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; bd->offs = this->badblockpos; bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; bd->pattern = scan_ff_pattern; @@ -1367,7 +1368,7 @@ int nand_default_bbt(struct mtd_info *mtd) } if (!this->badblock_pattern) - nand_create_default_bbt_descr(this); + nand_create_badblock_pattern(this); return nand_scan_bbt(mtd, this->badblock_pattern); } From 6d77b9d0af57409c918ab9501866233082546ba6 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Sep 2011 13:13:40 -0700 Subject: [PATCH 0447/1596] mtd: nand: invalidate cache on unaligned reads In rare cases, we are given an unaligned parameter `from' in `nand_do_read_ops()'. In such cases, we use the page cache (chip->buffers->databuf) as an intermediate buffer before dumping to the client buffer. However, there are also cases where this buffer is not cleanly reusable. In those cases, we need to make sure that we explicitly invalidate the cache. This patch prevents accidental reusage of the page cache, and for me, this solves some problems I come across when reading a corrupted BBT from flash (NAND_BBT_USE_FLASH and NAND_BBT_NO_OOB). Note: the rare "unaligned" case is a result of the extra BBT pattern + version located in the data area instead of OOB. Also, this patch disables caching on raw reads, since we are reading without error correction. This is, obviously, prone to errors and should not be cached. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_base.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index c9767b511dfe..51653d9e1438 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1479,14 +1479,22 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, else ret = chip->ecc.read_page(mtd, chip, bufpoi, page); - if (ret < 0) + if (ret < 0) { + if (!aligned) + /* Invalidate page cache */ + chip->pagebuf = -1; break; + } /* Transfer not aligned data */ if (!aligned) { if (!NAND_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - stats.failed)) + !(mtd->ecc_stats.failed - stats.failed) && + (ops->mode != MTD_OPS_RAW)) chip->pagebuf = realpage; + else + /* Invalidate page cache */ + chip->pagebuf = -1; memcpy(buf, chip->buffers->databuf + col, bytes); } From 75b66d8ccd5772b00a7328c2cf75bc506ec532a1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Sep 2011 13:13:41 -0700 Subject: [PATCH 0448/1596] mtd: nand: switch `check_pattern()' to standard `memcmp()' A portion of the `check_pattern()' function is basically a `memcmp()'. Since it's possible for `memcmp()' to be optimized for a particular architecture, we should use it instead. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/nand_bbt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 783093d1a2e5..5c9c0b2f09d4 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -107,10 +107,8 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc p += end; /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } + if (memcmp(p, td->pattern, td->len)) + return -1; if (td->options & NAND_BBT_SCANEMPTY) { p += td->len; From 75df713627f28f88b901b329c8857747545fd4ab Mon Sep 17 00:00:00 2001 From: Suresh Jayaraman Date: Wed, 21 Sep 2011 10:00:16 +0200 Subject: [PATCH 0449/1596] block: document blk-plug Thus spake Andrew Morton: "And I have the usual maintainability whine. If someone comes up to vmscan.c and sees it calling blk_start_plug(), how are they supposed to work out why that call is there? They go look at the blk_start_plug() definition and it is undocumented. I think we can do better than this?" Adapted from the LWN article - http://lwn.net/Articles/438256/ by Jens Axboe and from an earlier attempt by Shaohua Li to document blk-plug. [akpm@linux-foundation.org: grammatical and spelling tweaks] Signed-off-by: Suresh Jayaraman Cc: Shaohua Li Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- block/blk-core.c | 14 ++++++++++++++ include/linux/blkdev.h | 24 +++++++++++++++--------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 684d7eb33d43..97e9e5405b83 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2595,6 +2595,20 @@ EXPORT_SYMBOL(kblockd_schedule_delayed_work); #define PLUG_MAGIC 0x91827364 +/** + * blk_start_plug - initialize blk_plug and track it inside the task_struct + * @plug: The &struct blk_plug that needs to be initialized + * + * Description: + * Tracking blk_plug inside the task_struct will help with auto-flushing the + * pending I/O should the task end up blocking between blk_start_plug() and + * blk_finish_plug(). This is important from a performance perspective, but + * also ensures that we don't deadlock. For instance, if the task is blocking + * for a memory allocation, memory reclaim could end up wanting to free a + * page belonging to that request that is currently residing in our private + * plug. By flushing the pending I/O when the process goes to sleep, we avoid + * this kind of deadlock. + */ void blk_start_plug(struct blk_plug *plug) { struct task_struct *tsk = current; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c712efdafc3f..1978655faa3b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -860,17 +860,23 @@ struct request_queue *blk_alloc_queue_node(gfp_t, int); extern void blk_put_queue(struct request_queue *); /* - * Note: Code in between changing the blk_plug list/cb_list or element of such - * lists is preemptable, but such code can't do sleep (or be very careful), - * otherwise data is corrupted. For details, please check schedule() where - * blk_schedule_flush_plug() is called. + * blk_plug permits building a queue of related requests by holding the I/O + * fragments for a short period. This allows merging of sequential requests + * into single larger request. As the requests are moved from a per-task list to + * the device's request_queue in a batch, this results in improved scalability + * as the lock contention for request_queue lock is reduced. + * + * It is ok not to disable preemption when adding the request to the plug list + * or when attempting a merge, because blk_schedule_flush_list() will only flush + * the plug list when the task sleeps by itself. For details, please see + * schedule() where blk_schedule_flush_plug() is called. */ struct blk_plug { - unsigned long magic; - struct list_head list; - struct list_head cb_list; - unsigned int should_sort; - unsigned int count; + unsigned long magic; /* detect uninitialized use-cases */ + struct list_head list; /* requests */ + struct list_head cb_list; /* md requires an unplug callback */ + unsigned int should_sort; /* list to be sorted before flushing? */ + unsigned int count; /* number of queued requests */ }; #define BLK_MAX_REQUEST_COUNT 16 From 499337bb6511e665a236a6a947f819d98ea340c6 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 21 Sep 2011 10:01:22 +0200 Subject: [PATCH 0450/1596] block/blk-sysfs.c: fix kerneldoc references The kerneldoc for blk_release_queue() is referring to blk_cleanup_queue(). Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- block/blk-sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 0ee17b5e7fb6..adc923e9d1f8 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -455,11 +455,11 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr, } /** - * blk_cleanup_queue: - release a &struct request_queue when it is no longer needed - * @kobj: the kobj belonging of the request queue to be released + * blk_release_queue: - release a &struct request_queue when it is no longer needed + * @kobj: the kobj belonging to the request queue to be released * * Description: - * blk_cleanup_queue is the pair to blk_init_queue() or + * blk_release_queue is the pair to blk_init_queue() or * blk_queue_make_request(). It should be called when a request queue is * being released; typically when a block device is being de-registered. * Currently, its primary task it to free all the &struct request From 5a3a76e6c35fa236fc234d17a98edeb41d49130f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 21 Sep 2011 10:02:13 +0200 Subject: [PATCH 0451/1596] drivers/block/cpqarray.c: use pci_dev->revision This driver uses PCI_CLASS_REVISION instead of PCI_REVISION_ID, so it wasn't converted by commit 44c10138fd4bbc4b6 ("PCI: Change all drivers to use pci_device->revision"). Signed-off-by: Sergei Shtylyov Acked-by: Mike Miller Cc: Chirag Kantharia Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/cpqarray.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index b2fceb53e809..9125bbeacd4d 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -620,6 +620,7 @@ static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev) } vendor_id = pdev->vendor; device_id = pdev->device; + revision = pdev->revision; irq = pdev->irq; for(i=0; i<6; i++) @@ -632,7 +633,6 @@ static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev) } pci_read_config_word(pdev, PCI_COMMAND, &command); - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer); From 8a9c594422ecad912d6470888acdee9a1236ad68 Mon Sep 17 00:00:00 2001 From: Phillip Susi Date: Wed, 21 Sep 2011 10:02:13 +0200 Subject: [PATCH 0452/1596] drivers/block/loop.c: emit uevent on auto release The loopback driver failed to emit the change uevent when auto releasing the device. Fixed lo_release() to pass the bdev to loop_clr_fd() so it can emit the event. Signed-off-by: Phillip Susi Cc: Jens Axboe Cc: Ayan George Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b336433f8157..c2ce03cf3a58 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1583,7 +1583,7 @@ static int lo_release(struct gendisk *disk, fmode_t mode) * In autoclear mode, stop the loop thread * and remove configuration after last close. */ - err = loop_clr_fd(lo, NULL); + err = loop_clr_fd(lo, lo->lo_device); if (!err) goto out_unlocked; } else { From 4c823cc3d568277aa6340d8df6981e34f4c4dee5 Mon Sep 17 00:00:00 2001 From: Ayan George Date: Wed, 21 Sep 2011 10:02:13 +0200 Subject: [PATCH 0453/1596] drivers/block/loop.c: remove unnecessary bdev argument from loop_clr_fd() If the loop device is associated (lo->lo_state == Lo_bound), it will have a valid bdev pointed to by lo->lo_device. There is no reason to ever pass an additional block_device pointer. Signed-off-by: Ayan George Cc: Phillip Susi Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/loop.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c2ce03cf3a58..9b2f5d3c19ab 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1051,10 +1051,11 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, return err; } -static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) +static int loop_clr_fd(struct loop_device *lo) { struct file *filp = lo->lo_backing_file; gfp_t gfp = lo->old_gfp_mask; + struct block_device *bdev = lo->lo_device; if (lo->lo_state != Lo_bound) return -ENXIO; @@ -1372,7 +1373,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, break; case LOOP_CLR_FD: /* loop_clr_fd would have unlocked lo_ctl_mutex on success */ - err = loop_clr_fd(lo, bdev); + err = loop_clr_fd(lo); if (!err) goto out_unlocked; break; @@ -1583,7 +1584,7 @@ static int lo_release(struct gendisk *disk, fmode_t mode) * In autoclear mode, stop the loop thread * and remove configuration after last close. */ - err = loop_clr_fd(lo, lo->lo_device); + err = loop_clr_fd(lo); if (!err) goto out_unlocked; } else { From 6cf1d0b806a9e621ef1a8e90009e37f3446c2b9e Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 16 May 2011 18:02:43 +0200 Subject: [PATCH 0454/1596] powerpc/5200: mpc5200b.dtsi: add spi node address- and size-cells properties Both, #address-cells and #size-cells properties are required for spi bus node, so add them. Signed-off-by: Anatolij Gustschin --- arch/powerpc/boot/dts/mpc5200b.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/boot/dts/mpc5200b.dtsi b/arch/powerpc/boot/dts/mpc5200b.dtsi index bc27548e895d..7ab286ab5300 100644 --- a/arch/powerpc/boot/dts/mpc5200b.dtsi +++ b/arch/powerpc/boot/dts/mpc5200b.dtsi @@ -147,6 +147,8 @@ }; spi@f00 { + #address-cells = <1>; + #size-cells = <0>; compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi"; reg = <0xf00 0x20>; interrupts = <2 13 0 2 14 0>; From aa4593f2741946df5a47cbd679e1bc7da476e4bf Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 16 May 2011 18:02:44 +0200 Subject: [PATCH 0455/1596] powerpc/5200: dts: digsy_mtc.dts: update to add can, pci, serial and spi Add new nodes to describe more hardware the board is equipped with: - two can nodes for SJA1000 on localbus - pci node to support Coral-PA graphics controller - serial node for SC28L92 DUART on localbus - spi node for MSP430 device Also correct i2c eeprom node name. Signed-off-by: Heiko Schocher Signed-off-by: Anatolij Gustschin --- arch/powerpc/boot/dts/digsy_mtc.dts | 50 +++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/boot/dts/digsy_mtc.dts b/arch/powerpc/boot/dts/digsy_mtc.dts index 27bd267d631c..e205d17fd1f5 100644 --- a/arch/powerpc/boot/dts/digsy_mtc.dts +++ b/arch/powerpc/boot/dts/digsy_mtc.dts @@ -38,6 +38,14 @@ status = "disabled"; }; + spi@f00 { + msp430@0 { + compatible = "spidev"; + spi-max-frequency = <32000>; + reg = <0>; + }; + }; + psc@2000 { // PSC1 status = "disabled"; }; @@ -73,11 +81,16 @@ }; i2c@3d00 { - rtc@50 { + eeprom@50 { compatible = "at,24c08"; reg = <0x50>; }; + rtc@56 { + compatible = "mc,rv3029c2"; + reg = <0x56>; + }; + rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; @@ -90,11 +103,22 @@ }; pci@f0000d00 { - status = "disabled"; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = <0xc000 0 0 1 &mpc5200_pic 0 0 3 + 0xc000 0 0 2 &mpc5200_pic 0 0 3 + 0xc000 0 0 3 &mpc5200_pic 0 0 3 + 0xc000 0 0 4 &mpc5200_pic 0 0 3>; + clock-frequency = <0>; // From boot loader + interrupts = <2 8 0 2 9 0 2 10 0>; + bus-range = <0 0>; + ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000 + 0x02000000 0 0x90000000 0x90000000 0 0x10000000 + 0x01000000 0 0x00000000 0xa0000000 0 0x01000000>; }; localbus { - ranges = <0 0 0xff000000 0x1000000>; + ranges = <0 0 0xff000000 0x1000000 + 4 0 0x60000000 0x0001000>; // 16-bit flash device at LocalPlus Bus CS0 flash@0,0 { @@ -122,5 +146,25 @@ reg = <0x00f00000 0x100000>; }; }; + + can@4,0 { + compatible = "nxp,sja1000"; + reg = <4 0x000 0x80>; + nxp,external-clock-frequency = <24000000>; + interrupts = <1 2 3>; // Level-low + }; + + can@4,100 { + compatible = "nxp,sja1000"; + reg = <4 0x100 0x80>; + nxp,external-clock-frequency = <24000000>; + interrupts = <1 2 3>; // Level-low + }; + + serial@4,200 { + compatible = "nxp,sc28l92"; + reg = <4 0x200 0x10>; + interrupts = <1 3 3>; + }; }; }; From 1982c09a64b10c4407ef0b177ea7fcabc03d4add Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Tue, 7 Jun 2011 00:27:05 +0200 Subject: [PATCH 0456/1596] powerpc/5200: dts: digsy_mtc.dts: add timer0 and timer1 gpio properties timer0 and timer1 pins are used as simple GPIO on this board. Add gpio-controller and #gpio-cells properties to timer nodes so that we can control gpio lines using available MPC52xx GPT driver. Signed-off-by: Anatolij Gustschin --- arch/powerpc/boot/dts/digsy_mtc.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/powerpc/boot/dts/digsy_mtc.dts b/arch/powerpc/boot/dts/digsy_mtc.dts index e205d17fd1f5..2aad7ae435d4 100644 --- a/arch/powerpc/boot/dts/digsy_mtc.dts +++ b/arch/powerpc/boot/dts/digsy_mtc.dts @@ -23,7 +23,14 @@ soc5200@f0000000 { timer@600 { // General Purpose Timer + #gpio-cells = <2>; fsl,has-wdt; + gpio-controller; + }; + + timer@610 { + #gpio-cells = <2>; + gpio-controller; }; rtc@800 { From 5d9e6ac84363f28a7461e4afe4b7f24f4824a233 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 7 Jul 2011 14:49:50 +0200 Subject: [PATCH 0457/1596] powerpc/5200: dts: digsy_mtc.dts: enable both MSCAN nodes We use both MSCAN controllers on this board, so do not disable them in the device tree. Signed-off-by: Anatolij Gustschin --- arch/powerpc/boot/dts/digsy_mtc.dts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/powerpc/boot/dts/digsy_mtc.dts b/arch/powerpc/boot/dts/digsy_mtc.dts index 2aad7ae435d4..a7511f2d844d 100644 --- a/arch/powerpc/boot/dts/digsy_mtc.dts +++ b/arch/powerpc/boot/dts/digsy_mtc.dts @@ -37,14 +37,6 @@ status = "disabled"; }; - can@900 { - status = "disabled"; - }; - - can@980 { - status = "disabled"; - }; - spi@f00 { msp430@0 { compatible = "spidev"; From 40dc7e8b4ac5cdfcf13e3d80b71240f90ceb1f5b Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 1 Sep 2011 17:31:22 -0500 Subject: [PATCH 0458/1596] powerpc/5200: enable audio in the defconfig Audio support for the MPC5200 exists, so enable it by default. Signed-off-by: Timur Tabi Acked-by: Wolfram Sang Signed-off-by: Anatolij Gustschin --- arch/powerpc/configs/mpc5200_defconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig index e63f537b854a..2a1320fb2723 100644 --- a/arch/powerpc/configs/mpc5200_defconfig +++ b/arch/powerpc/configs/mpc5200_defconfig @@ -88,6 +88,18 @@ CONFIG_FB_RADEON=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_PCI is not set +# CONFIG_SND_PPC is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_USB is not set +CONFIG_SND_SOC=y +CONFIG_SND_SOC_MPC5200_I2S=y +CONFIG_SND_MPC52xx_SOC_PCM030=y +CONFIG_SND_MPC52xx_SOC_EFIKA=y CONFIG_HID_DRAGONRISE=y CONFIG_HID_GYRATION=y CONFIG_HID_TWINHAN=y From c68308dd50c3827a4ce77a1d70e0eb2d2521cafd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 21 Sep 2011 12:49:20 +0200 Subject: [PATCH 0459/1596] gpio: move mpc8xxx/512x gpio driver to drivers/gpio Move the driver to the place where it is expected to be nowadays. Also rename its CONFIG-name to match the rest and adapt the defconfigs. Finally, move selection of REQUIRE_GPIOLIB or WANTS_OPTIONAL_GPIOLIB to the platforms, because this option is per-platform and not per-driver. Signed-off-by: Wolfram Sang Cc: Anatolij Gustschin Cc: Grant Likely Cc: Benjamin Herrenschmidt Acked-by: Grant Likely Signed-off-by: Anatolij Gustschin --- arch/powerpc/configs/85xx/p1023rds_defconfig | 2 +- arch/powerpc/configs/85xx/xes_mpc85xx_defconfig | 2 +- arch/powerpc/configs/mpc85xx_defconfig | 2 +- arch/powerpc/configs/mpc85xx_smp_defconfig | 2 +- arch/powerpc/configs/ppc6xx_defconfig | 2 +- arch/powerpc/platforms/512x/Kconfig | 1 + arch/powerpc/platforms/83xx/Kconfig | 9 ++++++--- arch/powerpc/platforms/85xx/Kconfig | 12 ++++++++---- arch/powerpc/platforms/86xx/Kconfig | 1 + arch/powerpc/platforms/Kconfig | 10 ---------- arch/powerpc/sysdev/Makefile | 1 - drivers/gpio/Kconfig | 8 ++++++++ drivers/gpio/Makefile | 1 + .../mpc8xxx_gpio.c => drivers/gpio/gpio-mpc8xxx.c | 0 14 files changed, 30 insertions(+), 23 deletions(-) rename arch/powerpc/sysdev/mpc8xxx_gpio.c => drivers/gpio/gpio-mpc8xxx.c (100%) diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig index 3ff5a81c709f..c091aaf7685f 100644 --- a/arch/powerpc/configs/85xx/p1023rds_defconfig +++ b/arch/powerpc/configs/85xx/p1023rds_defconfig @@ -24,7 +24,7 @@ CONFIG_P1023_RDS=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y CONFIG_CPM2=y -CONFIG_MPC8xxx_GPIO=y +CONFIG_GPIO_MPC8XXX=y CONFIG_HIGHMEM=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig index 5ea3124518fd..1cd6fcb368e9 100644 --- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig +++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig @@ -20,7 +20,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set CONFIG_XES_MPC85xx=y -CONFIG_MPC8xxx_GPIO=y +CONFIG_GPIO_MPC8XXX=y CONFIG_HIGHMEM=y CONFIG_MATH_EMULATION=y CONFIG_SPARSE_IRQ=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index a3467bfb7671..250091207452 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -41,7 +41,7 @@ CONFIG_TQM8560=y CONFIG_SBC8548=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y -CONFIG_MPC8xxx_GPIO=y +CONFIG_GPIO_MPC8XXX=y CONFIG_HIGHMEM=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index 9693f6ed3da0..a4ba13b0ef1f 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -42,7 +42,7 @@ CONFIG_TQM8560=y CONFIG_SBC8548=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y -CONFIG_MPC8xxx_GPIO=y +CONFIG_GPIO_MPC8XXX=y CONFIG_HIGHMEM=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 04360f9b0109..c47f2becfbc3 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -70,7 +70,7 @@ CONFIG_TAU_AVERAGE=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y CONFIG_PPC_BESTCOMM=y -CONFIG_MPC8xxx_GPIO=y +CONFIG_GPIO_MPC8XXX=y CONFIG_MCU_MPC8349EMITX=m CONFIG_HIGHMEM=y CONFIG_NO_HZ=y diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index 27b0651221d1..b3ebce1aec07 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -6,6 +6,7 @@ config PPC_MPC512x select PPC_CLOCK select PPC_PCI_CHOICE select FSL_PCI if PCI + select ARCH_WANT_OPTIONAL_GPIOLIB config MPC5121_ADS bool "Freescale MPC5121E ADS" diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 73f4135f3a1a..670a033264c0 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -114,18 +114,21 @@ config KMETER1 endif -# used for usb +# used for usb & gpio config PPC_MPC831x bool + select ARCH_WANT_OPTIONAL_GPIOLIB # used for math-emu config PPC_MPC832x bool -# used for usb +# used for usb & gpio config PPC_MPC834x bool + select ARCH_WANT_OPTIONAL_GPIOLIB -# used for usb +# used for usb & gpio config PPC_MPC837x bool + select ARCH_WANT_OPTIONAL_GPIOLIB diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 498534cd5265..1b393f40c639 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -177,7 +177,8 @@ config P2040_RDB select PPC_E500MC select PHYS_64BIT select SWIOTLB - select MPC8xxx_GPIO + select ARCH_REQUIRE_GPIOLIB + select GPIO_MPC8XXX select HAS_RAPIDIO select PPC_EPAPR_HV_PIC help @@ -189,7 +190,8 @@ config P3041_DS select PPC_E500MC select PHYS_64BIT select SWIOTLB - select MPC8xxx_GPIO + select ARCH_REQUIRE_GPIOLIB + select GPIO_MPC8XXX select HAS_RAPIDIO select PPC_EPAPR_HV_PIC help @@ -201,7 +203,8 @@ config P4080_DS select PPC_E500MC select PHYS_64BIT select SWIOTLB - select MPC8xxx_GPIO + select ARCH_REQUIRE_GPIOLIB + select GPIO_MPC8XXX select HAS_RAPIDIO select PPC_EPAPR_HV_PIC help @@ -216,7 +219,8 @@ config P5020_DS select PPC_E500MC select PHYS_64BIT select SWIOTLB - select MPC8xxx_GPIO + select ARCH_REQUIRE_GPIOLIB + select GPIO_MPC8XXX select HAS_RAPIDIO select PPC_EPAPR_HV_PIC help diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index a0b5638c5dc8..8d6599d54ea6 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -4,6 +4,7 @@ menuconfig PPC_86xx depends on 6xx select FSL_SOC select ALTIVEC + select ARCH_WANT_OPTIONAL_GPIOLIB help The Freescale E600 SoCs have 74xx cores. diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 6de27d275728..9fdb9b6ab371 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -334,16 +334,6 @@ config OF_RTC source "arch/powerpc/sysdev/bestcomm/Kconfig" -config MPC8xxx_GPIO - bool "MPC512x/MPC8xxx GPIO support" - depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \ - FSL_SOC_BOOKE || PPC_86xx - select GENERIC_GPIO - select ARCH_REQUIRE_GPIOLIB - help - Say Y here if you're going to use hardware that connects to the - MPC512x/831x/834x/837x/8572/8610 GPIOs. - config SIMPLE_GPIO bool "Support for simple, memory-mapped GPIO controllers" depends on PPC diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index cf736ca0cf05..84e13253aec5 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) obj-$(CONFIG_FSL_PMC) += fsl_pmc.o obj-$(CONFIG_FSL_LBC) += fsl_lbc.o obj-$(CONFIG_FSL_GTM) += fsl_gtm.o -obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o obj-$(CONFIG_FSL_RIO) += fsl_rio.o diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d539efd96d4b..4744cf246d4a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -103,6 +103,14 @@ config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx +config GPIO_MPC8XXX + bool "MPC512x/MPC8xxx GPIO support" + depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \ + FSL_SOC_BOOKE || PPC_86xx + help + Say Y here if you're going to use hardware that connects to the + MPC512x/831x/834x/837x/8572/8610 GPIOs. + config GPIO_MSM_V1 tristate "Qualcomm MSM GPIO v1" depends on GPIOLIB && ARCH_MSM diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9588948c96f0..828bba9883c3 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o +obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/drivers/gpio/gpio-mpc8xxx.c similarity index 100% rename from arch/powerpc/sysdev/mpc8xxx_gpio.c rename to drivers/gpio/gpio-mpc8xxx.c From 7b72c9f8750e32b3b08fab1bfef43350866ae8d1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 21 Sep 2011 12:49:21 +0200 Subject: [PATCH 0460/1596] powerpc: update 512x-defconfig Activate all MPC512x related boards. Also enable GPIO-driver, SPI driver and at25 to test SPI. Enable DEVTMPFS. Bump to 3.1-rc6. Signed-off-by: Wolfram Sang Cc: Anatolij Gustschin Cc: Benjamin Herrenschmidt Signed-off-by: Anatolij Gustschin --- arch/powerpc/configs/mpc512x_defconfig | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/configs/mpc512x_defconfig b/arch/powerpc/configs/mpc512x_defconfig index c02bbb2fddf8..211fcc9ed700 100644 --- a/arch/powerpc/configs/mpc512x_defconfig +++ b/arch/powerpc/configs/mpc512x_defconfig @@ -1,9 +1,9 @@ CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +CONFIG_SPARSE_IRQ=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y CONFIG_MODULES=y @@ -13,10 +13,11 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_PPC_CHRP is not set CONFIG_PPC_MPC512x=y CONFIG_MPC5121_ADS=y +CONFIG_MPC5121_GENERIC=y +CONFIG_PDM360NG=y # CONFIG_PPC_PMAC is not set CONFIG_NO_HZ=y CONFIG_HZ_1000=y -CONFIG_SPARSE_IRQ=y # CONFIG_MIGRATION is not set # CONFIG_SECCOMP is not set # CONFIG_PCI is not set @@ -35,18 +36,16 @@ CONFIG_CAN=y CONFIG_CAN_RAW=y CONFIG_CAN_BCM=y CONFIG_CAN_VCAN=y -CONFIG_CAN_DEV=y CONFIG_CAN_MSCAN=y CONFIG_CAN_DEBUG_DEVICES=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y @@ -63,6 +62,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_BLK_DEV_XIP=y CONFIG_MISC_DEVICES=y CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y CONFIG_SCSI=y # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=y @@ -99,10 +99,14 @@ CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200 CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y +CONFIG_SPI=y +CONFIG_SPI_MPC512x_PSC=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_MPC8XXX=y # CONFIG_HWMON is not set CONFIG_MEDIA_SUPPORT=y CONFIG_VIDEO_DEV=y -# CONFIG_VIDEO_ALLOW_V4L1 is not set CONFIG_VIDEO_ADV_DEBUG=y # CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set CONFIG_VIDEO_SAA711X=y @@ -132,6 +136,5 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y # CONFIG_ENABLE_WARN_DEPRECATED is not set # CONFIG_ENABLE_MUST_CHECK is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_HW is not set From 25c29f9e3242071bca1bee7ad919baf1888ae436 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 20 Sep 2011 19:58:10 +0000 Subject: [PATCH 0461/1596] powerpc: Fix hugetlb with CONFIG_PPC_MM_SLICES=y Commit 41151e77a4 ("powerpc: Hugetlb for BookE") added some #ifdef CONFIG_MM_SLICES conditionals to hugetlb_get_unmapped_area() and vma_mmu_pagesize(). Unfortunately this is not the correct config symbol; it should be CONFIG_PPC_MM_SLICES. The result is that attempting to use hugetlbfs on 64-bit Power server processors results in an infinite stack recursion between get_unmapped_area() and hugetlb_get_unmapped_area(). This fixes it by changing the #ifdef to use CONFIG_PPC_MM_SLICES in those functions and also in book3e_hugetlb_preload(). Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/hugetlbpage-book3e.c | 2 +- arch/powerpc/mm/hugetlbpage.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c index 1295b7c1cdac..343ad0b87261 100644 --- a/arch/powerpc/mm/hugetlbpage-book3e.c +++ b/arch/powerpc/mm/hugetlbpage-book3e.c @@ -52,7 +52,7 @@ void book3e_hugetlb_preload(struct mm_struct *mm, unsigned long ea, pte_t pte) if (unlikely(is_kernel_addr(ea))) return; -#ifdef CONFIG_MM_SLICES +#ifdef CONFIG_PPC_MM_SLICES psize = mmu_get_tsize(get_slice_psize(mm, ea)); tsize = mmu_get_psize(psize); shift = mmu_psize_defs[psize].shift; diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 3a5f59dcbb33..48b65bedc04d 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -690,7 +690,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { -#ifdef CONFIG_MM_SLICES +#ifdef CONFIG_PPC_MM_SLICES struct hstate *hstate = hstate_file(file); int mmu_psize = shift_to_mmu_psize(huge_page_shift(hstate)); @@ -702,7 +702,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long vma_mmu_pagesize(struct vm_area_struct *vma) { -#ifdef CONFIG_MM_SLICES +#ifdef CONFIG_PPC_MM_SLICES unsigned int psize = get_slice_psize(vma->vm_mm, vma->vm_start); return 1UL << mmu_psize_to_shift(psize); From d12b524f8b2f4e45cabe8bc1501e8b967d543111 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Tue, 20 Sep 2011 03:07:24 +0000 Subject: [PATCH 0462/1596] powerpc: Reserve iommu page 0 Some devices have a dma-window that starts at the address 0. This allows DMA addresses to be mapped to this address and returned to drivers as a valid DMA address. Some drivers may not behave well in this case, since the address 0 is considered an error or not allocated. The solution to avoid this kind of error from happening is reserve the page addressed as 0 so it cannot be allocated for a DMA mapping. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/iommu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 961bb03413f3..0cfcf98aafca 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -501,6 +501,14 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) tbl->it_map = page_address(page); memset(tbl->it_map, 0, sz); + /* + * Reserve page 0 so it will not be used for any mappings. + * This avoids buggy drivers that consider page 0 to be invalid + * to crash the machine or even lose data. + */ + if (tbl->it_offset == 0) + set_bit(0, tbl->it_map); + tbl->it_hint = 0; tbl->it_largehint = tbl->it_halfpoint; spin_lock_init(&tbl->it_lock); From 5172ac1c6d2c1e631bc39ddf2d9334e05f69b022 Mon Sep 17 00:00:00 2001 From: Wolfram Stering Date: Fri, 23 Sep 2011 13:53:44 +0200 Subject: [PATCH 0463/1596] mtd: mxc_nand: preset_v1_v2: unlock all NAND flash blocks For NFC v1, the unlock end block address was 0x4000, which would only unlock the first 32 blocks of the NAND flash. Change that value to 0xffff to unlock all available blocks, as is done for NFC v21 as well. Signed-off-by: Michael Thalmeier Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/mxc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 4d4c67763cb0..74a43b818d0e 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -845,7 +845,7 @@ static void preset_v1_v2(struct mtd_info *mtd) writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3); } else if (nfc_is_v1()) { writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); - writew(0x4000, NFC_V1_UNLOCKEND_BLKADDR); + writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR); } else BUG(); From d5160ecffce97ad354caa5a8762edb8c350f9e84 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 26 Sep 2011 13:18:28 +0900 Subject: [PATCH 0464/1596] ARM: S3C64xx: Add LDOVDD supply for CODEC on Cragganmore Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/mach-crag6410.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index a0422a719996..ed332dd7bf4f 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -567,6 +567,7 @@ static struct regulator_init_data pvdd_1v2 __initdata = { }; static struct regulator_consumer_supply pvdd_1v8_consumers[] __initdata = { + REGULATOR_SUPPLY("LDOVDD", "1-001a"), REGULATOR_SUPPLY("PLLVDD", "1-001a"), REGULATOR_SUPPLY("DBVDD", "1-001a"), REGULATOR_SUPPLY("DBVDD1", "1-001a"), From bb36c44557a4fcbaa17c0f2776e12a05a691b432 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 26 Sep 2011 14:22:39 +1000 Subject: [PATCH 0465/1596] powerpc/pci: Don't configure PCIe settings when PCI_PROBE_ONLY is set We don't want to configure PCI Express Max Payload Size or Max Read Request Size on systems that set that flag. The firmware will have done it for us, and under hypervisors such as pHyp we don't even see the parent switches and bridges and thus can make no assumption on what values are safe to use. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/pci-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 1bd47f36b25f..677ecccbe10d 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1732,7 +1732,7 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose) hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); /* Configure PCI Express settings */ - if (bus) { + if (bus && !pci_has_flag(PCI_PROBE_ONLY)) { struct pci_bus *child; list_for_each_entry(child, &bus->children, node) { struct pci_dev *self = child->self; From ada766e959f1040311e05b11dd04921f4c29d5cc Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Fri, 23 Sep 2011 19:36:18 +0400 Subject: [PATCH 0466/1596] mtd: m25p80: add support for at25df321a spi data flash Signed-off-by: Mikhail Kshevetskiy Signed-off-by: Artem Bityutskiy --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index e6ba034c45bc..60177fe19582 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -655,6 +655,7 @@ static const struct spi_device_id m25p_ids[] = { { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, + { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, From 3e0996798a6a113efae9e0187c5581491bdb07a7 Mon Sep 17 00:00:00 2001 From: Yu Ke Date: Wed, 24 Mar 2010 11:01:13 -0700 Subject: [PATCH 0467/1596] xen/acpi: Domain0 acpi parser related platform hypercall This patches implements the xen_platform_op hypercall, to pass the parsed ACPI info to hypervisor. Signed-off-by: Yu Ke Signed-off-by: Tian Kevin Signed-off-by: Jeremy Fitzhardinge [v1: Added DEFINE_GUEST.. in appropiate headers] [v2: Ripped out typedefs] Signed-off-by: Konrad Rzeszutek Wilk --- arch/ia64/include/asm/xen/interface.h | 1 + arch/x86/include/asm/xen/interface.h | 1 + include/xen/interface/platform.h | 320 ++++++++++++++++++++++++++ include/xen/interface/xen.h | 1 + 4 files changed, 323 insertions(+) create mode 100644 include/xen/interface/platform.h diff --git a/arch/ia64/include/asm/xen/interface.h b/arch/ia64/include/asm/xen/interface.h index e951e740bdf2..1d2427d116e3 100644 --- a/arch/ia64/include/asm/xen/interface.h +++ b/arch/ia64/include/asm/xen/interface.h @@ -76,6 +76,7 @@ DEFINE_GUEST_HANDLE(char); DEFINE_GUEST_HANDLE(int); DEFINE_GUEST_HANDLE(long); DEFINE_GUEST_HANDLE(void); +DEFINE_GUEST_HANDLE(uint64_t); typedef unsigned long xen_pfn_t; DEFINE_GUEST_HANDLE(xen_pfn_t); diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h index 5d4922ad4b9b..a1f2db5f1170 100644 --- a/arch/x86/include/asm/xen/interface.h +++ b/arch/x86/include/asm/xen/interface.h @@ -55,6 +55,7 @@ DEFINE_GUEST_HANDLE(char); DEFINE_GUEST_HANDLE(int); DEFINE_GUEST_HANDLE(long); DEFINE_GUEST_HANDLE(void); +DEFINE_GUEST_HANDLE(uint64_t); #endif #ifndef HYPERVISOR_VIRT_START diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h new file mode 100644 index 000000000000..c1684680431b --- /dev/null +++ b/include/xen/interface/platform.h @@ -0,0 +1,320 @@ +/****************************************************************************** + * platform.h + * + * Hardware platform operations. Intended for use by domain-0 kernel. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2002-2006, K Fraser + */ + +#ifndef __XEN_PUBLIC_PLATFORM_H__ +#define __XEN_PUBLIC_PLATFORM_H__ + +#include "xen.h" + +#define XENPF_INTERFACE_VERSION 0x03000001 + +/* + * Set clock such that it would read after 00:00:00 UTC, + * 1 January, 1970 if the current system time was . + */ +#define XENPF_settime 17 +struct xenpf_settime { + /* IN variables. */ + uint32_t secs; + uint32_t nsecs; + uint64_t system_time; +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_settime_t); + +/* + * Request memory range (@mfn, @mfn+@nr_mfns-1) to have type @type. + * On x86, @type is an architecture-defined MTRR memory type. + * On success, returns the MTRR that was used (@reg) and a handle that can + * be passed to XENPF_DEL_MEMTYPE to accurately tear down the new setting. + * (x86-specific). + */ +#define XENPF_add_memtype 31 +struct xenpf_add_memtype { + /* IN variables. */ + unsigned long mfn; + uint64_t nr_mfns; + uint32_t type; + /* OUT variables. */ + uint32_t handle; + uint32_t reg; +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_add_memtype_t); + +/* + * Tear down an existing memory-range type. If @handle is remembered then it + * should be passed in to accurately tear down the correct setting (in case + * of overlapping memory regions with differing types). If it is not known + * then @handle should be set to zero. In all cases @reg must be set. + * (x86-specific). + */ +#define XENPF_del_memtype 32 +struct xenpf_del_memtype { + /* IN variables. */ + uint32_t handle; + uint32_t reg; +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_del_memtype_t); + +/* Read current type of an MTRR (x86-specific). */ +#define XENPF_read_memtype 33 +struct xenpf_read_memtype { + /* IN variables. */ + uint32_t reg; + /* OUT variables. */ + unsigned long mfn; + uint64_t nr_mfns; + uint32_t type; +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_read_memtype_t); + +#define XENPF_microcode_update 35 +struct xenpf_microcode_update { + /* IN variables. */ + GUEST_HANDLE(void) data; /* Pointer to microcode data */ + uint32_t length; /* Length of microcode data. */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_microcode_update_t); + +#define XENPF_platform_quirk 39 +#define QUIRK_NOIRQBALANCING 1 /* Do not restrict IO-APIC RTE targets */ +#define QUIRK_IOAPIC_BAD_REGSEL 2 /* IO-APIC REGSEL forgets its value */ +#define QUIRK_IOAPIC_GOOD_REGSEL 3 /* IO-APIC REGSEL behaves properly */ +struct xenpf_platform_quirk { + /* IN variables. */ + uint32_t quirk_id; +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_platform_quirk_t); + +#define XENPF_firmware_info 50 +#define XEN_FW_DISK_INFO 1 /* from int 13 AH=08/41/48 */ +#define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */ +#define XEN_FW_VBEDDC_INFO 3 /* from int 10 AX=4f15 */ +struct xenpf_firmware_info { + /* IN variables. */ + uint32_t type; + uint32_t index; + /* OUT variables. */ + union { + struct { + /* Int13, Fn48: Check Extensions Present. */ + uint8_t device; /* %dl: bios device number */ + uint8_t version; /* %ah: major version */ + uint16_t interface_support; /* %cx: support bitmap */ + /* Int13, Fn08: Legacy Get Device Parameters. */ + uint16_t legacy_max_cylinder; /* %cl[7:6]:%ch: max cyl # */ + uint8_t legacy_max_head; /* %dh: max head # */ + uint8_t legacy_sectors_per_track; /* %cl[5:0]: max sector # */ + /* Int13, Fn41: Get Device Parameters (as filled into %ds:%esi). */ + /* NB. First uint16_t of buffer must be set to buffer size. */ + GUEST_HANDLE(void) edd_params; + } disk_info; /* XEN_FW_DISK_INFO */ + struct { + uint8_t device; /* bios device number */ + uint32_t mbr_signature; /* offset 0x1b8 in mbr */ + } disk_mbr_signature; /* XEN_FW_DISK_MBR_SIGNATURE */ + struct { + /* Int10, AX=4F15: Get EDID info. */ + uint8_t capabilities; + uint8_t edid_transfer_time; + /* must refer to 128-byte buffer */ + GUEST_HANDLE(uchar) edid; + } vbeddc_info; /* XEN_FW_VBEDDC_INFO */ + } u; +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_firmware_info_t); + +#define XENPF_enter_acpi_sleep 51 +struct xenpf_enter_acpi_sleep { + /* IN variables */ + uint16_t pm1a_cnt_val; /* PM1a control value. */ + uint16_t pm1b_cnt_val; /* PM1b control value. */ + uint32_t sleep_state; /* Which state to enter (Sn). */ + uint32_t flags; /* Must be zero. */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_enter_acpi_sleep_t); + +#define XENPF_change_freq 52 +struct xenpf_change_freq { + /* IN variables */ + uint32_t flags; /* Must be zero. */ + uint32_t cpu; /* Physical cpu. */ + uint64_t freq; /* New frequency (Hz). */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_change_freq_t); + +/* + * Get idle times (nanoseconds since boot) for physical CPUs specified in the + * @cpumap_bitmap with range [0..@cpumap_nr_cpus-1]. The @idletime array is + * indexed by CPU number; only entries with the corresponding @cpumap_bitmap + * bit set are written to. On return, @cpumap_bitmap is modified so that any + * non-existent CPUs are cleared. Such CPUs have their @idletime array entry + * cleared. + */ +#define XENPF_getidletime 53 +struct xenpf_getidletime { + /* IN/OUT variables */ + /* IN: CPUs to interrogate; OUT: subset of IN which are present */ + GUEST_HANDLE(uchar) cpumap_bitmap; + /* IN variables */ + /* Size of cpumap bitmap. */ + uint32_t cpumap_nr_cpus; + /* Must be indexable for every cpu in cpumap_bitmap. */ + GUEST_HANDLE(uint64_t) idletime; + /* OUT variables */ + /* System time when the idletime snapshots were taken. */ + uint64_t now; +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_getidletime_t); + +#define XENPF_set_processor_pminfo 54 + +/* ability bits */ +#define XEN_PROCESSOR_PM_CX 1 +#define XEN_PROCESSOR_PM_PX 2 +#define XEN_PROCESSOR_PM_TX 4 + +/* cmd type */ +#define XEN_PM_CX 0 +#define XEN_PM_PX 1 +#define XEN_PM_TX 2 + +/* Px sub info type */ +#define XEN_PX_PCT 1 +#define XEN_PX_PSS 2 +#define XEN_PX_PPC 4 +#define XEN_PX_PSD 8 + +struct xen_power_register { + uint32_t space_id; + uint32_t bit_width; + uint32_t bit_offset; + uint32_t access_size; + uint64_t address; +}; + +struct xen_processor_csd { + uint32_t domain; /* domain number of one dependent group */ + uint32_t coord_type; /* coordination type */ + uint32_t num; /* number of processors in same domain */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_processor_csd); + +struct xen_processor_cx { + struct xen_power_register reg; /* GAS for Cx trigger register */ + uint8_t type; /* cstate value, c0: 0, c1: 1, ... */ + uint32_t latency; /* worst latency (ms) to enter/exit this cstate */ + uint32_t power; /* average power consumption(mW) */ + uint32_t dpcnt; /* number of dependency entries */ + GUEST_HANDLE(xen_processor_csd) dp; /* NULL if no dependency */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_processor_cx); + +struct xen_processor_flags { + uint32_t bm_control:1; + uint32_t bm_check:1; + uint32_t has_cst:1; + uint32_t power_setup_done:1; + uint32_t bm_rld_set:1; +}; + +struct xen_processor_power { + uint32_t count; /* number of C state entries in array below */ + struct xen_processor_flags flags; /* global flags of this processor */ + GUEST_HANDLE(xen_processor_cx) states; /* supported c states */ +}; + +struct xen_pct_register { + uint8_t descriptor; + uint16_t length; + uint8_t space_id; + uint8_t bit_width; + uint8_t bit_offset; + uint8_t reserved; + uint64_t address; +}; + +struct xen_processor_px { + uint64_t core_frequency; /* megahertz */ + uint64_t power; /* milliWatts */ + uint64_t transition_latency; /* microseconds */ + uint64_t bus_master_latency; /* microseconds */ + uint64_t control; /* control value */ + uint64_t status; /* success indicator */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_processor_px); + +struct xen_psd_package { + uint64_t num_entries; + uint64_t revision; + uint64_t domain; + uint64_t coord_type; + uint64_t num_processors; +}; + +struct xen_processor_performance { + uint32_t flags; /* flag for Px sub info type */ + uint32_t platform_limit; /* Platform limitation on freq usage */ + struct xen_pct_register control_register; + struct xen_pct_register status_register; + uint32_t state_count; /* total available performance states */ + GUEST_HANDLE(xen_processor_px) states; + struct xen_psd_package domain_info; + uint32_t shared_type; /* coordination type of this processor */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_processor_performance); + +struct xenpf_set_processor_pminfo { + /* IN variables */ + uint32_t id; /* ACPI CPU ID */ + uint32_t type; /* {XEN_PM_CX, XEN_PM_PX} */ + union { + struct xen_processor_power power;/* Cx: _CST/_CSD */ + struct xen_processor_performance perf; /* Px: _PPC/_PCT/_PSS/_PSD */ + }; +}; +DEFINE_GUEST_HANDLE_STRUCT(xenpf_set_processor_pminfo); + +struct xen_platform_op { + uint32_t cmd; + uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ + union { + struct xenpf_settime settime; + struct xenpf_add_memtype add_memtype; + struct xenpf_del_memtype del_memtype; + struct xenpf_read_memtype read_memtype; + struct xenpf_microcode_update microcode; + struct xenpf_platform_quirk platform_quirk; + struct xenpf_firmware_info firmware_info; + struct xenpf_enter_acpi_sleep enter_acpi_sleep; + struct xenpf_change_freq change_freq; + struct xenpf_getidletime getidletime; + struct xenpf_set_processor_pminfo set_pminfo; + uint8_t pad[128]; + } u; +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_platform_op_t); + +#endif /* __XEN_PUBLIC_PLATFORM_H__ */ diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h index 70213b4515eb..d83cc08921a8 100644 --- a/include/xen/interface/xen.h +++ b/include/xen/interface/xen.h @@ -453,6 +453,7 @@ struct start_info { /* These flags are passed in the 'flags' field of start_info_t. */ #define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */ #define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */ +#define SIF_PM_MASK (0xFF<<8) /* reserve 1 byte for xen-pm options */ typedef uint64_t cpumap_t; From eec07a9ecf428a680d72dc7f2428ea8bed80b84d Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 23 Sep 2011 11:44:17 -0700 Subject: [PATCH 0468/1596] xen: add dom0_op hypercall Signed-off-by: Jeremy Fitzhardinge --- arch/x86/include/asm/xen/hypercall.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index d240ea950519..0c9894e0ebfb 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -45,6 +45,7 @@ #include #include #include +#include /* * The hypercall asms have to meet several constraints: @@ -298,6 +299,13 @@ HYPERVISOR_set_timer_op(u64 timeout) return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); } +static inline int +HYPERVISOR_dom0_op(struct xen_platform_op *platform_op) +{ + platform_op->interface_version = XENPF_INTERFACE_VERSION; + return _hypercall1(int, dom0_op, platform_op); +} + static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value) { From fdb9eb9f155bfc0f8dc2fc88f90448b30c78ad97 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 26 Mar 2010 11:21:22 -0700 Subject: [PATCH 0469/1596] xen/dom0: set wallclock time in Xen Signed-off-by: Jeremy Fitzhardinge --- arch/x86/xen/time.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 5158c505bef9..8c9cdfa24657 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -200,8 +200,22 @@ static unsigned long xen_get_wallclock(void) static int xen_set_wallclock(unsigned long now) { + struct xen_platform_op op; + int rc; + /* do nothing for domU */ - return -1; + if (!xen_initial_domain()) + return -1; + + op.cmd = XENPF_settime; + op.u.settime.secs = now; + op.u.settime.nsecs = 0; + op.u.settime.system_time = xen_clocksource_read(); + + rc = HYPERVISOR_dom0_op(&op); + WARN(rc != 0, "XENPF_settime failed: now=%ld\n", now); + + return rc; } static struct clocksource xen_clocksource __read_mostly = { From b4dae6e1adaedc9c343b5f00332312d649600bdc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 25 Sep 2011 16:12:18 +0200 Subject: [PATCH 0470/1596] dmaengine: shdma: protect against the IRQ handler The IRQ handler of the shdma driver accesses common hardware registers, that are also accessed from other contexts. Therefore access to them has to be performed with interrupts disabled, not only with disabled bottom halves. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/shdma.c | 55 +++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 7f49235d14b9..e7bb7479b187 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -265,8 +265,9 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) struct sh_dmae_chan *sh_chan = to_sh_chan(tx->chan); dma_async_tx_callback callback = tx->callback; dma_cookie_t cookie; + unsigned long flags; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); cookie = sh_chan->common.cookie; cookie++; @@ -302,7 +303,7 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) tx->cookie, &last->async_tx, sh_chan->id, desc->hw.sar, desc->hw.tcr, desc->hw.dar); - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); return cookie; } @@ -374,24 +375,18 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) dmae_init(sh_chan); } - spin_lock_bh(&sh_chan->desc_lock); while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) { - spin_unlock_bh(&sh_chan->desc_lock); desc = kzalloc(sizeof(struct sh_desc), GFP_KERNEL); - if (!desc) { - spin_lock_bh(&sh_chan->desc_lock); + if (!desc) break; - } dma_async_tx_descriptor_init(&desc->async_tx, &sh_chan->common); desc->async_tx.tx_submit = sh_dmae_tx_submit; desc->mark = DESC_IDLE; - spin_lock_bh(&sh_chan->desc_lock); list_add(&desc->node, &sh_chan->ld_free); sh_chan->descs_allocated++; } - spin_unlock_bh(&sh_chan->desc_lock); if (!sh_chan->descs_allocated) { ret = -ENOMEM; @@ -405,6 +400,7 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) clear_bit(param->slave_id, sh_dmae_slave_used); etestused: efindslave: + chan->private = NULL; pm_runtime_put(sh_chan->dev); return ret; } @@ -437,12 +433,12 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) chan->private = NULL; } - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irq(&sh_chan->desc_lock); list_splice_init(&sh_chan->ld_free, &list); sh_chan->descs_allocated = 0; - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irq(&sh_chan->desc_lock); if (descs > 0) pm_runtime_put(sh_chan->dev); @@ -534,6 +530,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c struct sh_desc *first = NULL, *new = NULL /* compiler... */; LIST_HEAD(tx_list); int chunks = 0; + unsigned long irq_flags; int i; if (!sg_len) @@ -544,7 +541,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c (SH_DMA_TCR_MAX + 1); /* Have to lock the whole loop to protect against concurrent release */ - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, irq_flags); /* * Chaining: @@ -590,7 +587,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c /* Put them back on the free list, so, they don't get lost */ list_splice_tail(&tx_list, &sh_chan->ld_free); - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, irq_flags); return &first->async_tx; @@ -599,7 +596,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c new->mark = DESC_IDLE; list_splice(&tx_list, &sh_chan->ld_free); - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, irq_flags); return NULL; } @@ -661,6 +658,7 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { struct sh_dmae_chan *sh_chan = to_sh_chan(chan); + unsigned long flags; /* Only supports DMA_TERMINATE_ALL */ if (cmd != DMA_TERMINATE_ALL) @@ -669,7 +667,7 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, if (!chan) return -EINVAL; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); dmae_halt(sh_chan); if (!list_empty(&sh_chan->ld_queue)) { @@ -680,7 +678,7 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, sh_chan->xmit_shift; } - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); sh_dmae_chan_ld_cleanup(sh_chan, true); @@ -695,8 +693,9 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all dma_cookie_t cookie = 0; dma_async_tx_callback callback = NULL; void *param = NULL; + unsigned long flags; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); list_for_each_entry_safe(desc, _desc, &sh_chan->ld_queue, node) { struct dma_async_tx_descriptor *tx = &desc->async_tx; @@ -773,7 +772,7 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all */ sh_chan->completed_cookie = sh_chan->common.cookie; - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); if (callback) callback(param); @@ -796,10 +795,12 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) { struct sh_desc *desc; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irq(&sh_chan->desc_lock); /* DMA work check */ - if (dmae_is_busy(sh_chan)) - goto sh_chan_xfer_ld_queue_end; + if (dmae_is_busy(sh_chan)) { + spin_unlock_irq(&sh_chan->desc_lock); + return; + } /* Find the first not transferred descriptor */ list_for_each_entry(desc, &sh_chan->ld_queue, node) @@ -813,8 +814,7 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) break; } -sh_chan_xfer_ld_queue_end: - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irq(&sh_chan->desc_lock); } static void sh_dmae_memcpy_issue_pending(struct dma_chan *chan) @@ -831,6 +831,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, dma_cookie_t last_used; dma_cookie_t last_complete; enum dma_status status; + unsigned long flags; sh_dmae_chan_ld_cleanup(sh_chan, false); @@ -841,7 +842,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, BUG_ON(last_complete < 0); dma_set_tx_state(txstate, last_complete, last_used, 0); - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); status = dma_async_is_complete(cookie, last_complete, last_used); @@ -859,7 +860,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, } } - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); return status; } @@ -952,7 +953,7 @@ static void dmae_do_tasklet(unsigned long data) u32 sar_buf = sh_dmae_readl(sh_chan, SAR); u32 dar_buf = sh_dmae_readl(sh_chan, DAR); - spin_lock(&sh_chan->desc_lock); + spin_lock_irq(&sh_chan->desc_lock); list_for_each_entry(desc, &sh_chan->ld_queue, node) { if (desc->mark == DESC_SUBMITTED && ((desc->direction == DMA_FROM_DEVICE && @@ -965,7 +966,7 @@ static void dmae_do_tasklet(unsigned long data) break; } } - spin_unlock(&sh_chan->desc_lock); + spin_unlock_irq(&sh_chan->desc_lock); /* Next desc */ sh_chan_xfer_ld_queue(sh_chan); From 7a1cd9ad87979744e1510782b25c38feb9602739 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Aug 2011 16:55:27 +0200 Subject: [PATCH 0471/1596] dma: shdma: transfer based runtime PM Currently the shdma dmaengine driver uses runtime PM to save power, when no channel on the specific controller is requested by a user. This patch switches the driver to count individual DMA transfers. That way the controller can be powered down between transfers, even if some of its channels are in use. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/shdma.c | 94 ++++++++++++++++++++++++++++++++------------- drivers/dma/shdma.h | 7 ++++ 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index e7bb7479b187..81809c2b46ab 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -259,15 +259,23 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) return 0; } +static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan); + static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) { struct sh_desc *desc = tx_to_sh_desc(tx), *chunk, *last = desc, *c; struct sh_dmae_chan *sh_chan = to_sh_chan(tx->chan); + struct sh_dmae_slave *param = tx->chan->private; dma_async_tx_callback callback = tx->callback; dma_cookie_t cookie; - unsigned long flags; + bool power_up; - spin_lock_irqsave(&sh_chan->desc_lock, flags); + spin_lock_irq(&sh_chan->desc_lock); + + if (list_empty(&sh_chan->ld_queue)) + power_up = true; + else + power_up = false; cookie = sh_chan->common.cookie; cookie++; @@ -303,7 +311,38 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) tx->cookie, &last->async_tx, sh_chan->id, desc->hw.sar, desc->hw.tcr, desc->hw.dar); - spin_unlock_irqrestore(&sh_chan->desc_lock, flags); + if (power_up) { + sh_chan->pm_state = DMAE_PM_BUSY; + + pm_runtime_get(sh_chan->dev); + + spin_unlock_irq(&sh_chan->desc_lock); + + pm_runtime_barrier(sh_chan->dev); + + spin_lock_irq(&sh_chan->desc_lock); + + /* Have we been reset, while waiting? */ + if (sh_chan->pm_state != DMAE_PM_ESTABLISHED) { + dev_dbg(sh_chan->dev, "Bring up channel %d\n", + sh_chan->id); + if (param) { + const struct sh_dmae_slave_config *cfg = + param->config; + + dmae_set_dmars(sh_chan, cfg->mid_rid); + dmae_set_chcr(sh_chan, cfg->chcr); + } else { + dmae_init(sh_chan); + } + + if (sh_chan->pm_state == DMAE_PM_PENDING) + sh_chan_xfer_ld_queue(sh_chan); + sh_chan->pm_state = DMAE_PM_ESTABLISHED; + } + } + + spin_unlock_irq(&sh_chan->desc_lock); return cookie; } @@ -347,8 +386,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) struct sh_dmae_slave *param = chan->private; int ret; - pm_runtime_get_sync(sh_chan->dev); - /* * This relies on the guarantee from dmaengine that alloc_chan_resources * never runs concurrently with itself or free_chan_resources. @@ -368,11 +405,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) } param->config = cfg; - - dmae_set_dmars(sh_chan, cfg->mid_rid); - dmae_set_chcr(sh_chan, cfg->chcr); - } else { - dmae_init(sh_chan); } while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) { @@ -401,7 +433,6 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) etestused: efindslave: chan->private = NULL; - pm_runtime_put(sh_chan->dev); return ret; } @@ -413,7 +444,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) struct sh_dmae_chan *sh_chan = to_sh_chan(chan); struct sh_desc *desc, *_desc; LIST_HEAD(list); - int descs = sh_chan->descs_allocated; /* Protect against ISR */ spin_lock_irq(&sh_chan->desc_lock); @@ -440,9 +470,6 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) spin_unlock_irq(&sh_chan->desc_lock); - if (descs > 0) - pm_runtime_put(sh_chan->dev); - list_for_each_entry_safe(desc, _desc, &list, node) kfree(desc); } @@ -676,7 +703,6 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, struct sh_desc, node); desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) << sh_chan->xmit_shift; - } spin_unlock_irqrestore(&sh_chan->desc_lock, flags); @@ -761,7 +787,13 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all async_tx_test_ack(&desc->async_tx)) || all) { /* Remove from ld_queue list */ desc->mark = DESC_IDLE; + list_move(&desc->node, &sh_chan->ld_free); + + if (list_empty(&sh_chan->ld_queue)) { + dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id); + pm_runtime_put(sh_chan->dev); + } } } @@ -791,16 +823,14 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all) ; } +/* Called under spin_lock_irq(&sh_chan->desc_lock) */ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) { struct sh_desc *desc; - spin_lock_irq(&sh_chan->desc_lock); /* DMA work check */ - if (dmae_is_busy(sh_chan)) { - spin_unlock_irq(&sh_chan->desc_lock); + if (dmae_is_busy(sh_chan)) return; - } /* Find the first not transferred descriptor */ list_for_each_entry(desc, &sh_chan->ld_queue, node) @@ -813,14 +843,18 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) dmae_start(sh_chan); break; } - - spin_unlock_irq(&sh_chan->desc_lock); } static void sh_dmae_memcpy_issue_pending(struct dma_chan *chan) { struct sh_dmae_chan *sh_chan = to_sh_chan(chan); - sh_chan_xfer_ld_queue(sh_chan); + + spin_lock_irq(&sh_chan->desc_lock); + if (sh_chan->pm_state == DMAE_PM_ESTABLISHED) + sh_chan_xfer_ld_queue(sh_chan); + else + sh_chan->pm_state = DMAE_PM_PENDING; + spin_unlock_irq(&sh_chan->desc_lock); } static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, @@ -913,6 +947,12 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev) list_splice_init(&sh_chan->ld_queue, &dl); + if (!list_empty(&dl)) { + dev_dbg(sh_chan->dev, "Bring down channel %d\n", sh_chan->id); + pm_runtime_put(sh_chan->dev); + } + sh_chan->pm_state = DMAE_PM_ESTABLISHED; + spin_unlock(&sh_chan->desc_lock); /* Complete all */ @@ -966,10 +1006,10 @@ static void dmae_do_tasklet(unsigned long data) break; } } - spin_unlock_irq(&sh_chan->desc_lock); - /* Next desc */ sh_chan_xfer_ld_queue(sh_chan); + spin_unlock_irq(&sh_chan->desc_lock); + sh_dmae_chan_ld_cleanup(sh_chan, false); } @@ -1037,7 +1077,9 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, return -ENOMEM; } - /* copy struct dma_device */ + new_sh_chan->pm_state = DMAE_PM_ESTABLISHED; + + /* reference struct dma_device */ new_sh_chan->common.device = &shdev->common; new_sh_chan->dev = shdev->common.dev; diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index dc56576f9fdb..2b55a276dc5b 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -23,6 +23,12 @@ struct device; +enum dmae_pm_state { + DMAE_PM_ESTABLISHED, + DMAE_PM_BUSY, + DMAE_PM_PENDING, +}; + struct sh_dmae_chan { dma_cookie_t completed_cookie; /* The maximum cookie completed */ spinlock_t desc_lock; /* Descriptor operation lock */ @@ -38,6 +44,7 @@ struct sh_dmae_chan { u32 __iomem *base; char dev_id[16]; /* unique name per DMAC of channel */ int pm_error; + enum dmae_pm_state pm_state; }; struct sh_dmae_device { From 66857b3a9e88ac6f6e279eaa06b84367e662c0dd Mon Sep 17 00:00:00 2001 From: Jimi Xenidis Date: Fri, 23 Sep 2011 05:40:46 +0000 Subject: [PATCH 0472/1596] powerpc: Fix xmon for systems without MSR[RI] Based on patch by David Gibson xmon has a longstanding bug on systems which are SMP-capable but lack the MSR[RI] bit. In these cases, xmon invoked by IPI on secondary CPUs will not properly keep quiet, but will print stuff, thereby garbling the primary xmon's output. This patch fixes it, by ignoring the RI bit if the processor does not support it. There's already a version of this for 4xx upstream, which we'll need to extend to other RI-lacking CPUs at some point. For now this adds Book3e processors to the mix. Signed-off-by: Jimi Xenidis Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/xmon/xmon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 42541bbcc7fa..13f82f847669 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -340,8 +340,8 @@ int cpus_are_in_xmon(void) static inline int unrecoverable_excp(struct pt_regs *regs) { -#ifdef CONFIG_4xx - /* We have no MSR_RI bit on 4xx, so we simply return false */ +#if defined(CONFIG_4xx) || defined(CONFIG_BOOK3E) + /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */ return 0; #else return ((regs->msr & MSR_RI) == 0); From e69b742a6793dc5bf16f6eedca534d4bc10d68b2 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 26 Sep 2011 19:37:57 +0000 Subject: [PATCH 0473/1596] powerpc/ptrace: Fix build with gcc 4.6 gcc (rightfully) complains that we are accessing beyond the end of the fpr array (we do, to access the fpscr). The only sane thing to do (whether anything in that code can be called remotely sane is debatable) is to special case fpscr and handle it as a separate statement. I initially tried to do it it by making the array access conditional to index < PT_FPSCR and using a 3rd else leg but for some reason gcc was unable to understand it and still spewed the warning. So I ended up with something a tad more intricated but it seems to build on 32-bit and on 64-bit with and without VSX. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/ptrace.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 05b7dd217f60..18447c4fbad3 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1497,9 +1497,14 @@ long arch_ptrace(struct task_struct *child, long request, if (index < PT_FPR0) { tmp = ptrace_get_reg(child, (int) index); } else { + unsigned int fpidx = index - PT_FPR0; + flush_fp_to_thread(child); - tmp = ((unsigned long *)child->thread.fpr) - [TS_FPRWIDTH * (index - PT_FPR0)]; + if (fpidx < (PT_FPSCR - PT_FPR0)) + tmp = ((unsigned long *)child->thread.fpr) + [fpidx * TS_FPRWIDTH]; + else + tmp = child->thread.fpscr.val; } ret = put_user(tmp, datalp); break; @@ -1525,9 +1530,14 @@ long arch_ptrace(struct task_struct *child, long request, if (index < PT_FPR0) { ret = ptrace_put_reg(child, index, data); } else { + unsigned int fpidx = index - PT_FPR0; + flush_fp_to_thread(child); - ((unsigned long *)child->thread.fpr) - [TS_FPRWIDTH * (index - PT_FPR0)] = data; + if (fpidx < (PT_FPSCR - PT_FPR0)) + ((unsigned long *)child->thread.fpr) + [fpidx * TS_FPRWIDTH] = data; + else + child->thread.fpscr.val = data; ret = 0; } break; From d15f02eb4e8992cfacfca2ff306e5585bcf721d1 Mon Sep 17 00:00:00 2001 From: "Carl E. Love" Date: Wed, 28 Sep 2011 11:23:33 +0000 Subject: [PATCH 0474/1596] powerpc/perf_event: Fix Power6 L1 cache read & write event codes] The current L1 cache read event code 0x80082 only counts for thread 0. The event code 0x280030 should be used to count events on thread 0 and 1. The patch fixes the event code for the L1 cache read. The current L1 cache write event code 0x80086 only counts for thread 0. The event code 0x180032 should be used to count events on thread 0 and 1. The patch fixes the event code for the L1 cache write. FYI, the documentation lists three event codes for the L1 cache read event and three event codes for the L1 cache write event. The event description for the event codes is as follows: L1 cache read requests 0x80082 LSU 0 only L1 cache read requests 0x8008A LSU 1 only L1 cache read requests 0x80030 LSU 1 or LSU 0, counter 2 only. L1 cache store requests 0x80086 LSU 0 only L1 cache store requests 0x8008E LSU 1 only L1 cache store requests 0x80032 LSU 0 or LSU 1, counter 1 only. There can only be one request from either LSU 0 or 1 active at a time. Signed-off-by: Carl Love Acked-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/power6-pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/kernel/power6-pmu.c index 03b95e2c6d65..0bbc901e7efc 100644 --- a/arch/powerpc/kernel/power6-pmu.c +++ b/arch/powerpc/kernel/power6-pmu.c @@ -487,8 +487,8 @@ static int power6_generic_events[] = { */ static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */ - [C(OP_READ)] = { 0x80082, 0x80080 }, - [C(OP_WRITE)] = { 0x80086, 0x80088 }, + [C(OP_READ)] = { 0x280030, 0x80080 }, + [C(OP_WRITE)] = { 0x180032, 0x80088 }, [C(OP_PREFETCH)] = { 0x810a4, 0 }, }, [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */ From 7680057cc4c7d9caada12767831bfd9738dd7b43 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 28 Sep 2011 20:51:46 +0000 Subject: [PATCH 0475/1596] powerpc: Don't try OPAL takeover on old 970 blades The firmware on old 970 blades supports some kind of takeover called "TNK takeover" which will crash if we try to probe for OPAL takeover, so don't do it. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/prom_init.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index e96f5d0d2c78..b4fa66127495 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1313,6 +1313,16 @@ static void prom_query_opal(void) { long rc; + /* We must not query for OPAL presence on a machine that + * supports TNK takeover (970 blades), as this uses the same + * h-call with different arguments and will crash + */ + if (PHANDLE_VALID(call_prom("finddevice", 1, 1, + ADDR("/tnk-memory-map")))) { + prom_printf("TNK takeover detected, skipping OPAL check\n"); + return; + } + prom_printf("Querying for OPAL presence... "); rc = opal_query_takeover(&RELOC(prom_opal_size), &RELOC(prom_opal_align)); From a542ad1bafc7df9fc16de8a6894b350a4df75572 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 13 Jun 2011 19:52:59 +0200 Subject: [PATCH 0476/1596] btrfs: added helper functions to iterate backrefs These helper functions iterate back references and call a function for each backref. There is also a function to resolve an inode to a path in the file system. Signed-off-by: Jan Schmidt --- fs/btrfs/Makefile | 3 +- fs/btrfs/backref.c | 776 +++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/backref.h | 62 ++++ fs/btrfs/ioctl.h | 11 + 4 files changed, 851 insertions(+), 1 deletion(-) create mode 100644 fs/btrfs/backref.c create mode 100644 fs/btrfs/backref.h diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index 40e6ac08c21f..89b6ce3634fd 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -7,6 +7,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o \ - compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o + compression.o delayed-ref.o relocation.o delayed-inode.o backref.o \ + scrub.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c new file mode 100644 index 000000000000..2351df0de450 --- /dev/null +++ b/fs/btrfs/backref.c @@ -0,0 +1,776 @@ +/* + * Copyright (C) 2011 STRATO. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include "ctree.h" +#include "disk-io.h" +#include "backref.h" + +struct __data_ref { + struct list_head list; + u64 inum; + u64 root; + u64 extent_data_item_offset; +}; + +struct __shared_ref { + struct list_head list; + u64 disk_byte; +}; + +static int __inode_info(u64 inum, u64 ioff, u8 key_type, + struct btrfs_root *fs_root, struct btrfs_path *path, + struct btrfs_key *found_key) +{ + int ret; + struct btrfs_key key; + struct extent_buffer *eb; + + key.type = key_type; + key.objectid = inum; + key.offset = ioff; + + ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); + if (ret < 0) + return ret; + + eb = path->nodes[0]; + if (ret && path->slots[0] >= btrfs_header_nritems(eb)) { + ret = btrfs_next_leaf(fs_root, path); + if (ret) + return ret; + eb = path->nodes[0]; + } + + btrfs_item_key_to_cpu(eb, found_key, path->slots[0]); + if (found_key->type != key.type || found_key->objectid != key.objectid) + return 1; + + return 0; +} + +/* + * this makes the path point to (inum INODE_ITEM ioff) + */ +int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, + struct btrfs_path *path) +{ + struct btrfs_key key; + return __inode_info(inum, ioff, BTRFS_INODE_ITEM_KEY, fs_root, path, + &key); +} + +static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, + struct btrfs_path *path, + struct btrfs_key *found_key) +{ + return __inode_info(inum, ioff, BTRFS_INODE_REF_KEY, fs_root, path, + found_key); +} + +/* + * this iterates to turn a btrfs_inode_ref into a full filesystem path. elements + * of the path are separated by '/' and the path is guaranteed to be + * 0-terminated. the path is only given within the current file system. + * Therefore, it never starts with a '/'. the caller is responsible to provide + * "size" bytes in "dest". the dest buffer will be filled backwards. finally, + * the start point of the resulting string is returned. this pointer is within + * dest, normally. + * in case the path buffer would overflow, the pointer is decremented further + * as if output was written to the buffer, though no more output is actually + * generated. that way, the caller can determine how much space would be + * required for the path to fit into the buffer. in that case, the returned + * value will be smaller than dest. callers must check this! + */ +static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, + struct btrfs_inode_ref *iref, + struct extent_buffer *eb_in, u64 parent, + char *dest, u32 size) +{ + u32 len; + int slot; + u64 next_inum; + int ret; + s64 bytes_left = size - 1; + struct extent_buffer *eb = eb_in; + struct btrfs_key found_key; + + if (bytes_left >= 0) + dest[bytes_left] = '\0'; + + while (1) { + len = btrfs_inode_ref_name_len(eb, iref); + bytes_left -= len; + if (bytes_left >= 0) + read_extent_buffer(eb, dest + bytes_left, + (unsigned long)(iref + 1), len); + if (eb != eb_in) + free_extent_buffer(eb); + ret = inode_ref_info(parent, 0, fs_root, path, &found_key); + if (ret) + break; + next_inum = found_key.offset; + + /* regular exit ahead */ + if (parent == next_inum) + break; + + slot = path->slots[0]; + eb = path->nodes[0]; + /* make sure we can use eb after releasing the path */ + if (eb != eb_in) + atomic_inc(&eb->refs); + btrfs_release_path(path); + + iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); + parent = next_inum; + --bytes_left; + if (bytes_left >= 0) + dest[bytes_left] = '/'; + } + + btrfs_release_path(path); + + if (ret) + return ERR_PTR(ret); + + return dest + bytes_left; +} + +/* + * this makes the path point to (logical EXTENT_ITEM *) + * returns BTRFS_EXTENT_FLAG_DATA for data, BTRFS_EXTENT_FLAG_TREE_BLOCK for + * tree blocks and <0 on error. + */ +int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, + struct btrfs_path *path, struct btrfs_key *found_key) +{ + int ret; + u64 flags; + u32 item_size; + struct extent_buffer *eb; + struct btrfs_extent_item *ei; + struct btrfs_key key; + + key.type = BTRFS_EXTENT_ITEM_KEY; + key.objectid = logical; + key.offset = (u64)-1; + + ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); + if (ret < 0) + return ret; + ret = btrfs_previous_item(fs_info->extent_root, path, + 0, BTRFS_EXTENT_ITEM_KEY); + if (ret < 0) + return ret; + + btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); + if (found_key->type != BTRFS_EXTENT_ITEM_KEY || + found_key->objectid > logical || + found_key->objectid + found_key->offset <= logical) + return -ENOENT; + + eb = path->nodes[0]; + item_size = btrfs_item_size_nr(eb, path->slots[0]); + BUG_ON(item_size < sizeof(*ei)); + + ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); + flags = btrfs_extent_flags(eb, ei); + + if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) + return BTRFS_EXTENT_FLAG_TREE_BLOCK; + if (flags & BTRFS_EXTENT_FLAG_DATA) + return BTRFS_EXTENT_FLAG_DATA; + + return -EIO; +} + +/* + * helper function to iterate extent inline refs. ptr must point to a 0 value + * for the first call and may be modified. it is used to track state. + * if more refs exist, 0 is returned and the next call to + * __get_extent_inline_ref must pass the modified ptr parameter to get the + * next ref. after the last ref was processed, 1 is returned. + * returns <0 on error + */ +static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb, + struct btrfs_extent_item *ei, u32 item_size, + struct btrfs_extent_inline_ref **out_eiref, + int *out_type) +{ + unsigned long end; + u64 flags; + struct btrfs_tree_block_info *info; + + if (!*ptr) { + /* first call */ + flags = btrfs_extent_flags(eb, ei); + if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { + info = (struct btrfs_tree_block_info *)(ei + 1); + *out_eiref = + (struct btrfs_extent_inline_ref *)(info + 1); + } else { + *out_eiref = (struct btrfs_extent_inline_ref *)(ei + 1); + } + *ptr = (unsigned long)*out_eiref; + if ((void *)*ptr >= (void *)ei + item_size) + return -ENOENT; + } + + end = (unsigned long)ei + item_size; + *out_eiref = (struct btrfs_extent_inline_ref *)*ptr; + *out_type = btrfs_extent_inline_ref_type(eb, *out_eiref); + + *ptr += btrfs_extent_inline_ref_size(*out_type); + WARN_ON(*ptr > end); + if (*ptr == end) + return 1; /* last */ + + return 0; +} + +/* + * reads the tree block backref for an extent. tree level and root are returned + * through out_level and out_root. ptr must point to a 0 value for the first + * call and may be modified (see __get_extent_inline_ref comment). + * returns 0 if data was provided, 1 if there was no more data to provide or + * <0 on error. + */ +int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, + struct btrfs_extent_item *ei, u32 item_size, + u64 *out_root, u8 *out_level) +{ + int ret; + int type; + struct btrfs_tree_block_info *info; + struct btrfs_extent_inline_ref *eiref; + + if (*ptr == (unsigned long)-1) + return 1; + + while (1) { + ret = __get_extent_inline_ref(ptr, eb, ei, item_size, + &eiref, &type); + if (ret < 0) + return ret; + + if (type == BTRFS_TREE_BLOCK_REF_KEY || + type == BTRFS_SHARED_BLOCK_REF_KEY) + break; + + if (ret == 1) + return 1; + } + + /* we can treat both ref types equally here */ + info = (struct btrfs_tree_block_info *)(ei + 1); + *out_root = btrfs_extent_inline_ref_offset(eb, eiref); + *out_level = btrfs_tree_block_level(eb, info); + + if (ret == 1) + *ptr = (unsigned long)-1; + + return 0; +} + +static int __data_list_add(struct list_head *head, u64 inum, + u64 extent_data_item_offset, u64 root) +{ + struct __data_ref *ref; + + ref = kmalloc(sizeof(*ref), GFP_NOFS); + if (!ref) + return -ENOMEM; + + ref->inum = inum; + ref->extent_data_item_offset = extent_data_item_offset; + ref->root = root; + list_add_tail(&ref->list, head); + + return 0; +} + +static int __data_list_add_eb(struct list_head *head, struct extent_buffer *eb, + struct btrfs_extent_data_ref *dref) +{ + return __data_list_add(head, btrfs_extent_data_ref_objectid(eb, dref), + btrfs_extent_data_ref_offset(eb, dref), + btrfs_extent_data_ref_root(eb, dref)); +} + +static int __shared_list_add(struct list_head *head, u64 disk_byte) +{ + struct __shared_ref *ref; + + ref = kmalloc(sizeof(*ref), GFP_NOFS); + if (!ref) + return -ENOMEM; + + ref->disk_byte = disk_byte; + list_add_tail(&ref->list, head); + + return 0; +} + +static int __iter_shared_inline_ref_inodes(struct btrfs_fs_info *fs_info, + u64 logical, u64 inum, + u64 extent_data_item_offset, + u64 extent_offset, + struct btrfs_path *path, + struct list_head *data_refs, + iterate_extent_inodes_t *iterate, + void *ctx) +{ + u64 ref_root; + u32 item_size; + struct btrfs_key key; + struct extent_buffer *eb; + struct btrfs_extent_item *ei; + struct btrfs_extent_inline_ref *eiref; + struct __data_ref *ref; + int ret; + int type; + int last; + unsigned long ptr = 0; + + WARN_ON(!list_empty(data_refs)); + ret = extent_from_logical(fs_info, logical, path, &key); + if (ret & BTRFS_EXTENT_FLAG_DATA) + ret = -EIO; + if (ret < 0) + goto out; + + eb = path->nodes[0]; + ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); + item_size = btrfs_item_size_nr(eb, path->slots[0]); + + ret = 0; + ref_root = 0; + /* + * as done in iterate_extent_inodes, we first build a list of refs to + * iterate, then free the path and then iterate them to avoid deadlocks. + */ + do { + last = __get_extent_inline_ref(&ptr, eb, ei, item_size, + &eiref, &type); + if (last < 0) { + ret = last; + goto out; + } + if (type == BTRFS_TREE_BLOCK_REF_KEY || + type == BTRFS_SHARED_BLOCK_REF_KEY) { + ref_root = btrfs_extent_inline_ref_offset(eb, eiref); + ret = __data_list_add(data_refs, inum, + extent_data_item_offset, + ref_root); + } + } while (!ret && !last); + + btrfs_release_path(path); + + if (ref_root == 0) { + printk(KERN_ERR "btrfs: failed to find tree block ref " + "for shared data backref %llu\n", logical); + WARN_ON(1); + ret = -EIO; + } + +out: + while (!list_empty(data_refs)) { + ref = list_first_entry(data_refs, struct __data_ref, list); + list_del(&ref->list); + if (!ret) + ret = iterate(ref->inum, extent_offset + + ref->extent_data_item_offset, + ref->root, ctx); + kfree(ref); + } + + return ret; +} + +static int __iter_shared_inline_ref(struct btrfs_fs_info *fs_info, + u64 logical, u64 orig_extent_item_objectid, + u64 extent_offset, struct btrfs_path *path, + struct list_head *data_refs, + iterate_extent_inodes_t *iterate, + void *ctx) +{ + u64 disk_byte; + struct btrfs_key key; + struct btrfs_file_extent_item *fi; + struct extent_buffer *eb; + int slot; + int nritems; + int ret; + int found = 0; + + eb = read_tree_block(fs_info->tree_root, logical, + fs_info->tree_root->leafsize, 0); + if (!eb) + return -EIO; + + /* + * from the shared data ref, we only have the leaf but we need + * the key. thus, we must look into all items and see that we + * find one (some) with a reference to our extent item. + */ + nritems = btrfs_header_nritems(eb); + for (slot = 0; slot < nritems; ++slot) { + btrfs_item_key_to_cpu(eb, &key, slot); + if (key.type != BTRFS_EXTENT_DATA_KEY) + continue; + fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); + if (!fi) { + free_extent_buffer(eb); + return -EIO; + } + disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); + if (disk_byte != orig_extent_item_objectid) { + if (found) + break; + else + continue; + } + ++found; + ret = __iter_shared_inline_ref_inodes(fs_info, logical, + key.objectid, + key.offset, + extent_offset, path, + data_refs, + iterate, ctx); + if (ret) + break; + } + + if (!found) { + printk(KERN_ERR "btrfs: failed to follow shared data backref " + "to parent %llu\n", logical); + WARN_ON(1); + ret = -EIO; + } + + free_extent_buffer(eb); + return ret; +} + +/* + * calls iterate() for every inode that references the extent identified by + * the given parameters. will use the path given as a parameter and return it + * released. + * when the iterator function returns a non-zero value, iteration stops. + */ +int iterate_extent_inodes(struct btrfs_fs_info *fs_info, + struct btrfs_path *path, + u64 extent_item_objectid, + u64 extent_offset, + iterate_extent_inodes_t *iterate, void *ctx) +{ + unsigned long ptr = 0; + int last; + int ret; + int type; + u64 logical; + u32 item_size; + struct btrfs_extent_inline_ref *eiref; + struct btrfs_extent_data_ref *dref; + struct extent_buffer *eb; + struct btrfs_extent_item *ei; + struct btrfs_key key; + struct list_head data_refs = LIST_HEAD_INIT(data_refs); + struct list_head shared_refs = LIST_HEAD_INIT(shared_refs); + struct __data_ref *ref_d; + struct __shared_ref *ref_s; + + eb = path->nodes[0]; + ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); + item_size = btrfs_item_size_nr(eb, path->slots[0]); + + /* first we iterate the inline refs, ... */ + do { + last = __get_extent_inline_ref(&ptr, eb, ei, item_size, + &eiref, &type); + if (last == -ENOENT) { + ret = 0; + break; + } + if (last < 0) { + ret = last; + break; + } + + if (type == BTRFS_EXTENT_DATA_REF_KEY) { + dref = (struct btrfs_extent_data_ref *)(&eiref->offset); + ret = __data_list_add_eb(&data_refs, eb, dref); + } else if (type == BTRFS_SHARED_DATA_REF_KEY) { + logical = btrfs_extent_inline_ref_offset(eb, eiref); + ret = __shared_list_add(&shared_refs, logical); + } + } while (!ret && !last); + + /* ... then we proceed to in-tree references and ... */ + while (!ret) { + ++path->slots[0]; + if (path->slots[0] > btrfs_header_nritems(eb)) { + ret = btrfs_next_leaf(fs_info->extent_root, path); + if (ret) { + if (ret == 1) + ret = 0; /* we're done */ + break; + } + eb = path->nodes[0]; + } + btrfs_item_key_to_cpu(eb, &key, path->slots[0]); + if (key.objectid != extent_item_objectid) + break; + if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { + dref = btrfs_item_ptr(eb, path->slots[0], + struct btrfs_extent_data_ref); + ret = __data_list_add_eb(&data_refs, eb, dref); + } else if (key.type == BTRFS_SHARED_DATA_REF_KEY) { + ret = __shared_list_add(&shared_refs, key.offset); + } + } + + btrfs_release_path(path); + + /* + * ... only at the very end we can process the refs we found. this is + * because the iterator function we call is allowed to make tree lookups + * and we have to avoid deadlocks. additionally, we need more tree + * lookups ourselves for shared data refs. + */ + while (!list_empty(&data_refs)) { + ref_d = list_first_entry(&data_refs, struct __data_ref, list); + list_del(&ref_d->list); + if (!ret) + ret = iterate(ref_d->inum, extent_offset + + ref_d->extent_data_item_offset, + ref_d->root, ctx); + kfree(ref_d); + } + + while (!list_empty(&shared_refs)) { + ref_s = list_first_entry(&shared_refs, struct __shared_ref, + list); + list_del(&ref_s->list); + if (!ret) + ret = __iter_shared_inline_ref(fs_info, + ref_s->disk_byte, + extent_item_objectid, + extent_offset, path, + &data_refs, + iterate, ctx); + kfree(ref_s); + } + + return ret; +} + +int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, + struct btrfs_path *path, + iterate_extent_inodes_t *iterate, void *ctx) +{ + int ret; + u64 offset; + struct btrfs_key found_key; + + ret = extent_from_logical(fs_info, logical, path, + &found_key); + if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) + ret = -EINVAL; + if (ret < 0) + return ret; + + offset = logical - found_key.objectid; + ret = iterate_extent_inodes(fs_info, path, found_key.objectid, + offset, iterate, ctx); + + return ret; +} + +static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, + struct btrfs_path *path, + iterate_irefs_t *iterate, void *ctx) +{ + int ret; + int slot; + u32 cur; + u32 len; + u32 name_len; + u64 parent = 0; + int found = 0; + struct extent_buffer *eb; + struct btrfs_item *item; + struct btrfs_inode_ref *iref; + struct btrfs_key found_key; + + while (1) { + ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path, + &found_key); + if (ret < 0) + break; + if (ret) { + ret = found ? 0 : -ENOENT; + break; + } + ++found; + + parent = found_key.offset; + slot = path->slots[0]; + eb = path->nodes[0]; + /* make sure we can use eb after releasing the path */ + atomic_inc(&eb->refs); + btrfs_release_path(path); + + item = btrfs_item_nr(eb, slot); + iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); + + for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) { + name_len = btrfs_inode_ref_name_len(eb, iref); + /* path must be released before calling iterate()! */ + ret = iterate(parent, iref, eb, ctx); + if (ret) { + free_extent_buffer(eb); + break; + } + len = sizeof(*iref) + name_len; + iref = (struct btrfs_inode_ref *)((char *)iref + len); + } + free_extent_buffer(eb); + } + + btrfs_release_path(path); + + return ret; +} + +/* + * returns 0 if the path could be dumped (probably truncated) + * returns <0 in case of an error + */ +static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, + struct extent_buffer *eb, void *ctx) +{ + struct inode_fs_paths *ipath = ctx; + char *fspath; + char *fspath_min; + int i = ipath->fspath->elem_cnt; + const int s_ptr = sizeof(char *); + u32 bytes_left; + + bytes_left = ipath->fspath->bytes_left > s_ptr ? + ipath->fspath->bytes_left - s_ptr : 0; + + fspath_min = (char *)ipath->fspath->str + (i + 1) * s_ptr; + fspath = iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb, + inum, fspath_min, bytes_left); + if (IS_ERR(fspath)) + return PTR_ERR(fspath); + + if (fspath > fspath_min) { + ipath->fspath->str[i] = fspath; + ++ipath->fspath->elem_cnt; + ipath->fspath->bytes_left = fspath - fspath_min; + } else { + ++ipath->fspath->elem_missed; + ipath->fspath->bytes_missing += fspath_min - fspath; + ipath->fspath->bytes_left = 0; + } + + return 0; +} + +/* + * this dumps all file system paths to the inode into the ipath struct, provided + * is has been created large enough. each path is zero-terminated and accessed + * from ipath->fspath->str[i]. + * when it returns, there are ipath->fspath->elem_cnt number of paths available + * in ipath->fspath->str[]. when the allocated space wasn't sufficient, the + * number of missed paths in recored in ipath->fspath->elem_missed, otherwise, + * it's zero. ipath->fspath->bytes_missing holds the number of bytes that would + * have been needed to return all paths. + */ +int paths_from_inode(u64 inum, struct inode_fs_paths *ipath) +{ + return iterate_irefs(inum, ipath->fs_root, ipath->btrfs_path, + inode_to_path, ipath); +} + +/* + * allocates space to return multiple file system paths for an inode. + * total_bytes to allocate are passed, note that space usable for actual path + * information will be total_bytes - sizeof(struct inode_fs_paths). + * the returned pointer must be freed with free_ipath() in the end. + */ +struct btrfs_data_container *init_data_container(u32 total_bytes) +{ + struct btrfs_data_container *data; + size_t alloc_bytes; + + alloc_bytes = max_t(size_t, total_bytes, sizeof(*data)); + data = kmalloc(alloc_bytes, GFP_NOFS); + if (!data) + return ERR_PTR(-ENOMEM); + + if (total_bytes >= sizeof(*data)) { + data->bytes_left = total_bytes - sizeof(*data); + data->bytes_missing = 0; + } else { + data->bytes_missing = sizeof(*data) - total_bytes; + data->bytes_left = 0; + } + + data->elem_cnt = 0; + data->elem_missed = 0; + + return data; +} + +/* + * allocates space to return multiple file system paths for an inode. + * total_bytes to allocate are passed, note that space usable for actual path + * information will be total_bytes - sizeof(struct inode_fs_paths). + * the returned pointer must be freed with free_ipath() in the end. + */ +struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, + struct btrfs_path *path) +{ + struct inode_fs_paths *ifp; + struct btrfs_data_container *fspath; + + fspath = init_data_container(total_bytes); + if (IS_ERR(fspath)) + return (void *)fspath; + + ifp = kmalloc(sizeof(*ifp), GFP_NOFS); + if (!ifp) { + kfree(fspath); + return ERR_PTR(-ENOMEM); + } + + ifp->btrfs_path = path; + ifp->fspath = fspath; + ifp->fs_root = fs_root; + + return ifp; +} + +void free_ipath(struct inode_fs_paths *ipath) +{ + kfree(ipath); +} diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h new file mode 100644 index 000000000000..92618837cb8f --- /dev/null +++ b/fs/btrfs/backref.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 STRATO. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#ifndef __BTRFS_BACKREF__ +#define __BTRFS_BACKREF__ + +#include "ioctl.h" + +struct inode_fs_paths { + struct btrfs_path *btrfs_path; + struct btrfs_root *fs_root; + struct btrfs_data_container *fspath; +}; + +typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root, + void *ctx); +typedef int (iterate_irefs_t)(u64 parent, struct btrfs_inode_ref *iref, + struct extent_buffer *eb, void *ctx); + +int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, + struct btrfs_path *path); + +int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, + struct btrfs_path *path, struct btrfs_key *found_key); + +int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, + struct btrfs_extent_item *ei, u32 item_size, + u64 *out_root, u8 *out_level); + +int iterate_extent_inodes(struct btrfs_fs_info *fs_info, + struct btrfs_path *path, + u64 extent_item_objectid, + u64 extent_offset, + iterate_extent_inodes_t *iterate, void *ctx); + +int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, + struct btrfs_path *path, + iterate_extent_inodes_t *iterate, void *ctx); + +int paths_from_inode(u64 inum, struct inode_fs_paths *ipath); + +struct btrfs_data_container *init_data_container(u32 total_bytes); +struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, + struct btrfs_path *path); +void free_ipath(struct inode_fs_paths *ipath); + +#endif diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index ad1ea789fcb4..1857e3871843 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h @@ -193,6 +193,17 @@ struct btrfs_ioctl_space_args { struct btrfs_ioctl_space_info spaces[0]; }; +struct btrfs_data_container { + __u32 bytes_left; /* out -- bytes not needed to deliver output */ + __u32 bytes_missing; /* out -- additional bytes needed for result */ + __u32 elem_cnt; /* out */ + __u32 elem_missed; /* out */ + union { + char *str[0]; /* out */ + __u64 val[0]; /* out */ + }; +}; + #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ From 13db62b7a1e8c64763a93c155091620f85ff8920 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 13 Jun 2011 19:56:13 +0200 Subject: [PATCH 0477/1596] btrfs scrub: added unverified_errors In normal operation, scrub is reading data sequentially in large portions. In case of an i/o error, we try to find the corrupted area(s) by issuing page sized read requests. With this commit we increment the unverified_errors counter if all of the small size requests succeed. Userland patches carrying such conspicous events to the administrator should already be around. Signed-off-by: Jan Schmidt --- fs/btrfs/scrub.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index a8d03d5efb5d..35099fa97d56 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -201,18 +201,25 @@ struct scrub_dev *scrub_setup_dev(struct btrfs_device *dev) * recheck_error gets called for every page in the bio, even though only * one may be bad */ -static void scrub_recheck_error(struct scrub_bio *sbio, int ix) +static int scrub_recheck_error(struct scrub_bio *sbio, int ix) { + struct scrub_dev *sdev = sbio->sdev; + u64 sector = (sbio->physical + ix * PAGE_SIZE) >> 9; + if (sbio->err) { - if (scrub_fixup_io(READ, sbio->sdev->dev->bdev, - (sbio->physical + ix * PAGE_SIZE) >> 9, + if (scrub_fixup_io(READ, sbio->sdev->dev->bdev, sector, sbio->bio->bi_io_vec[ix].bv_page) == 0) { if (scrub_fixup_check(sbio, ix) == 0) - return; + return 0; } } + spin_lock(&sdev->stat_lock); + ++sdev->stat.read_errors; + spin_unlock(&sdev->stat_lock); + scrub_fixup(sbio, ix); + return 1; } static int scrub_fixup_check(struct scrub_bio *sbio, int ix) @@ -382,8 +389,14 @@ static void scrub_checksum(struct btrfs_work *work) int ret; if (sbio->err) { + ret = 0; for (i = 0; i < sbio->count; ++i) - scrub_recheck_error(sbio, i); + ret |= scrub_recheck_error(sbio, i); + if (!ret) { + spin_lock(&sdev->stat_lock); + ++sdev->stat.unverified_errors; + spin_unlock(&sdev->stat_lock); + } sbio->bio->bi_flags &= ~(BIO_POOL_MASK - 1); sbio->bio->bi_flags |= 1 << BIO_UPTODATE; @@ -396,10 +409,6 @@ static void scrub_checksum(struct btrfs_work *work) bi->bv_offset = 0; bi->bv_len = PAGE_SIZE; } - - spin_lock(&sdev->stat_lock); - ++sdev->stat.read_errors; - spin_unlock(&sdev->stat_lock); goto out; } for (i = 0; i < sbio->count; ++i) { @@ -420,8 +429,14 @@ static void scrub_checksum(struct btrfs_work *work) WARN_ON(1); } kunmap_atomic(buffer, KM_USER0); - if (ret) - scrub_recheck_error(sbio, i); + if (ret) { + ret = scrub_recheck_error(sbio, i); + if (!ret) { + spin_lock(&sdev->stat_lock); + ++sdev->stat.unverified_errors; + spin_unlock(&sdev->stat_lock); + } + } } out: From 558540c17771eaf89b1a3be39aa2c8bc837da1a6 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 13 Jun 2011 19:59:12 +0200 Subject: [PATCH 0478/1596] btrfs scrub: print paths of corrupted files While scrubbing, we may encounter various errors. Previously, a logical address was printed to the log only. Now, all paths belonging to that address are resolved and printed separately. That should work for hardlinks as well as reflinks. Signed-off-by: Jan Schmidt --- fs/btrfs/scrub.c | 169 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 35099fa97d56..221fd5c48736 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -17,10 +17,12 @@ */ #include +#include #include "ctree.h" #include "volumes.h" #include "disk-io.h" #include "ordered-data.h" +#include "backref.h" /* * This is only the first step towards a full-features scrub. It reads all @@ -100,6 +102,19 @@ struct scrub_dev { spinlock_t stat_lock; }; +struct scrub_warning { + struct btrfs_path *path; + u64 extent_item_size; + char *scratch_buf; + char *msg_buf; + const char *errstr; + sector_t sector; + u64 logical; + struct btrfs_device *dev; + int msg_bufsize; + int scratch_bufsize; +}; + static void scrub_free_csums(struct scrub_dev *sdev) { while (!list_empty(&sdev->csum_list)) { @@ -195,6 +210,143 @@ struct scrub_dev *scrub_setup_dev(struct btrfs_device *dev) return ERR_PTR(-ENOMEM); } +static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx) +{ + u64 isize; + u32 nlink; + int ret; + int i; + struct extent_buffer *eb; + struct btrfs_inode_item *inode_item; + struct scrub_warning *swarn = ctx; + struct btrfs_fs_info *fs_info = swarn->dev->dev_root->fs_info; + struct inode_fs_paths *ipath = NULL; + struct btrfs_root *local_root; + struct btrfs_key root_key; + + root_key.objectid = root; + root_key.type = BTRFS_ROOT_ITEM_KEY; + root_key.offset = (u64)-1; + local_root = btrfs_read_fs_root_no_name(fs_info, &root_key); + if (IS_ERR(local_root)) { + ret = PTR_ERR(local_root); + goto err; + } + + ret = inode_item_info(inum, 0, local_root, swarn->path); + if (ret) { + btrfs_release_path(swarn->path); + goto err; + } + + eb = swarn->path->nodes[0]; + inode_item = btrfs_item_ptr(eb, swarn->path->slots[0], + struct btrfs_inode_item); + isize = btrfs_inode_size(eb, inode_item); + nlink = btrfs_inode_nlink(eb, inode_item); + btrfs_release_path(swarn->path); + + ipath = init_ipath(4096, local_root, swarn->path); + ret = paths_from_inode(inum, ipath); + + if (ret < 0) + goto err; + + /* + * we deliberately ignore the bit ipath might have been too small to + * hold all of the paths here + */ + for (i = 0; i < ipath->fspath->elem_cnt; ++i) + printk(KERN_WARNING "btrfs: %s at logical %llu on dev " + "%s, sector %llu, root %llu, inode %llu, offset %llu, " + "length %llu, links %u (path: %s)\n", swarn->errstr, + swarn->logical, swarn->dev->name, + (unsigned long long)swarn->sector, root, inum, offset, + min(isize - offset, (u64)PAGE_SIZE), nlink, + ipath->fspath->str[i]); + + free_ipath(ipath); + return 0; + +err: + printk(KERN_WARNING "btrfs: %s at logical %llu on dev " + "%s, sector %llu, root %llu, inode %llu, offset %llu: path " + "resolving failed with ret=%d\n", swarn->errstr, + swarn->logical, swarn->dev->name, + (unsigned long long)swarn->sector, root, inum, offset, ret); + + free_ipath(ipath); + return 0; +} + +static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio, + int ix) +{ + struct btrfs_device *dev = sbio->sdev->dev; + struct btrfs_fs_info *fs_info = dev->dev_root->fs_info; + struct btrfs_path *path; + struct btrfs_key found_key; + struct extent_buffer *eb; + struct btrfs_extent_item *ei; + struct scrub_warning swarn; + u32 item_size; + int ret; + u64 ref_root; + u8 ref_level; + unsigned long ptr = 0; + const int bufsize = 4096; + u64 extent_offset; + + path = btrfs_alloc_path(); + + swarn.scratch_buf = kmalloc(bufsize, GFP_NOFS); + swarn.msg_buf = kmalloc(bufsize, GFP_NOFS); + swarn.sector = (sbio->physical + ix * PAGE_SIZE) >> 9; + swarn.logical = sbio->logical + ix * PAGE_SIZE; + swarn.errstr = errstr; + swarn.dev = dev; + swarn.msg_bufsize = bufsize; + swarn.scratch_bufsize = bufsize; + + if (!path || !swarn.scratch_buf || !swarn.msg_buf) + goto out; + + ret = extent_from_logical(fs_info, swarn.logical, path, &found_key); + if (ret < 0) + goto out; + + extent_offset = swarn.logical - found_key.objectid; + swarn.extent_item_size = found_key.offset; + + eb = path->nodes[0]; + ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); + item_size = btrfs_item_size_nr(eb, path->slots[0]); + + if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) { + do { + ret = tree_backref_for_extent(&ptr, eb, ei, item_size, + &ref_root, &ref_level); + printk(KERN_WARNING "%s at logical %llu on dev %s, " + "sector %llu: metadata %s (level %d) in tree " + "%llu\n", errstr, swarn.logical, dev->name, + (unsigned long long)swarn.sector, + ref_level ? "node" : "leaf", + ret < 0 ? -1 : ref_level, + ret < 0 ? -1 : ref_root); + } while (ret != 1); + } else { + swarn.path = path; + iterate_extent_inodes(fs_info, path, found_key.objectid, + extent_offset, + scrub_print_warning_inode, &swarn); + } + +out: + btrfs_free_path(path); + kfree(swarn.scratch_buf); + kfree(swarn.msg_buf); +} + /* * scrub_recheck_error gets called when either verification of the page * failed or the bio failed to read, e.g. with EIO. In the latter case, @@ -205,6 +357,8 @@ static int scrub_recheck_error(struct scrub_bio *sbio, int ix) { struct scrub_dev *sdev = sbio->sdev; u64 sector = (sbio->physical + ix * PAGE_SIZE) >> 9; + static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); if (sbio->err) { if (scrub_fixup_io(READ, sbio->sdev->dev->bdev, sector, @@ -212,6 +366,11 @@ static int scrub_recheck_error(struct scrub_bio *sbio, int ix) if (scrub_fixup_check(sbio, ix) == 0) return 0; } + if (__ratelimit(&_rs)) + scrub_print_warning("i/o error", sbio, ix); + } else { + if (__ratelimit(&_rs)) + scrub_print_warning("checksum error", sbio, ix); } spin_lock(&sdev->stat_lock); @@ -326,9 +485,8 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) ++sdev->stat.corrected_errors; spin_unlock(&sdev->stat_lock); - if (printk_ratelimit()) - printk(KERN_ERR "btrfs: fixed up at %llu\n", - (unsigned long long)logical); + printk_ratelimited(KERN_ERR "btrfs: fixed up error at logical %llu\n", + (unsigned long long)logical); return; uncorrectable: @@ -337,9 +495,8 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) ++sdev->stat.uncorrectable_errors; spin_unlock(&sdev->stat_lock); - if (printk_ratelimit()) - printk(KERN_ERR "btrfs: unable to fixup at %llu\n", - (unsigned long long)logical); + printk_ratelimited(KERN_ERR "btrfs: unable to fixup (regular) error at " + "logical %llu\n", (unsigned long long)logical); } static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector, From 193ea74b2729e6ddc08fb6bde6e15a3bd4d94071 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 13 Jun 2011 19:56:54 +0200 Subject: [PATCH 0479/1596] btrfs scrub: bugfix: mirror_num off by one Fix the mirror_num determination in scrub_stripe. The rest of the scrub code did not use mirror_num for anything important and that error went unnoticed. The nodatasum fixup patch of this set depends on a correct mirror_num. Signed-off-by: Jan Schmidt --- fs/btrfs/scrub.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 221fd5c48736..59caf8fcd1c7 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -452,7 +452,7 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) * first find a good copy */ for (i = 0; i < multi->num_stripes; ++i) { - if (i == sbio->spag[ix].mirror_num) + if (i + 1 == sbio->spag[ix].mirror_num) continue; if (scrub_fixup_io(READ, multi->stripes[i].dev->bdev, @@ -930,21 +930,21 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, if (map->type & BTRFS_BLOCK_GROUP_RAID0) { offset = map->stripe_len * num; increment = map->stripe_len * map->num_stripes; - mirror_num = 0; + mirror_num = 1; } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { int factor = map->num_stripes / map->sub_stripes; offset = map->stripe_len * (num / map->sub_stripes); increment = map->stripe_len * factor; - mirror_num = num % map->sub_stripes; + mirror_num = num % map->sub_stripes + 1; } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) { increment = map->stripe_len; - mirror_num = num % map->num_stripes; + mirror_num = num % map->num_stripes + 1; } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { increment = map->stripe_len; - mirror_num = num % map->num_stripes; + mirror_num = num % map->num_stripes + 1; } else { increment = map->stripe_len; - mirror_num = 0; + mirror_num = 1; } path = btrfs_alloc_path(); From 8ddc7d9cd0a00062247c732b96386ec2462bdbc7 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 13 Jun 2011 20:02:58 +0200 Subject: [PATCH 0480/1596] btrfs: add mirror_num to extent_read_full_page Currently, extent_read_full_page always assumes we are trying to read mirror 0, which generally is the best we can do. To add flexibility, pass it as a parameter. This will be needed by scrub fixup code. Signed-off-by: Jan Schmidt --- fs/btrfs/disk-io.c | 2 +- fs/btrfs/extent_io.c | 6 +++--- fs/btrfs/extent_io.h | 2 +- fs/btrfs/inode.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 07b3ac662e19..dc0343802535 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -908,7 +908,7 @@ static int btree_readpage(struct file *file, struct page *page) { struct extent_io_tree *tree; tree = &BTRFS_I(page->mapping->host)->io_tree; - return extent_read_full_page(tree, page, btree_get_extent); + return extent_read_full_page(tree, page, btree_get_extent, 0); } static int btree_releasepage(struct page *page, gfp_t gfp_flags) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index d418164a35f1..afebb95e3490 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2076,16 +2076,16 @@ static int __extent_read_full_page(struct extent_io_tree *tree, } int extent_read_full_page(struct extent_io_tree *tree, struct page *page, - get_extent_t *get_extent) + get_extent_t *get_extent, int mirror_num) { struct bio *bio = NULL; unsigned long bio_flags = 0; int ret; - ret = __extent_read_full_page(tree, page, get_extent, &bio, 0, + ret = __extent_read_full_page(tree, page, get_extent, &bio, mirror_num, &bio_flags); if (bio) - ret = submit_one_bio(READ, bio, 0, bio_flags); + ret = submit_one_bio(READ, bio, mirror_num, bio_flags); return ret; } diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 7b2f0c3e7929..a9dd994bf826 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -185,7 +185,7 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end, int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask); int extent_read_full_page(struct extent_io_tree *tree, struct page *page, - get_extent_t *get_extent); + get_extent_t *get_extent, int mirror_num); int __init extent_io_init(void); void extent_io_exit(void); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b2d004ad66a0..efee8c7cfa45 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6289,7 +6289,7 @@ int btrfs_readpage(struct file *file, struct page *page) { struct extent_io_tree *tree; tree = &BTRFS_I(page->mapping->host)->io_tree; - return extent_read_full_page(tree, page, btrfs_get_extent); + return extent_read_full_page(tree, page, btrfs_get_extent, 0); } static int btrfs_writepage(struct page *page, struct writeback_control *wbc) From e12fa9cd390f8e93a9144bd99bd6f6ed316fbc1e Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 17 Jun 2011 15:55:21 +0200 Subject: [PATCH 0481/1596] btrfs scrub: use int for mirror_num, not u64 the rest of the code uses int mirror_num, and so should scrub Signed-off-by: Jan Schmidt --- fs/btrfs/scrub.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 59caf8fcd1c7..41a01147b959 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -65,7 +65,7 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix); struct scrub_page { u64 flags; /* extent flags */ u64 generation; - u64 mirror_num; + int mirror_num; int have_csum; u8 csum[BTRFS_CSUM_SIZE]; }; @@ -776,7 +776,7 @@ static int scrub_submit(struct scrub_dev *sdev) } static int scrub_page(struct scrub_dev *sdev, u64 logical, u64 len, - u64 physical, u64 flags, u64 gen, u64 mirror_num, + u64 physical, u64 flags, u64 gen, int mirror_num, u8 *csum, int force) { struct scrub_bio *sbio; @@ -873,7 +873,7 @@ static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len, /* scrub extent tries to collect up to 64 kB for each bio */ static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len, - u64 physical, u64 flags, u64 gen, u64 mirror_num) + u64 physical, u64 flags, u64 gen, int mirror_num) { int ret; u8 csum[BTRFS_CSUM_SIZE]; @@ -919,7 +919,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, u64 physical; u64 logical; u64 generation; - u64 mirror_num; + int mirror_num; u64 increment = map->stripe_len; u64 offset; From 0ef8e45158f97dde4801b535e25f70f7caf01a27 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 13 Jun 2011 20:04:15 +0200 Subject: [PATCH 0482/1596] btrfs scrub: add fixup code for errors on nodatasum files This removes a FIXME comment and introduces the first part of nodatasum fixup: It gets the corresponding inode for a logical address and triggers a regular readpage for the corrupted sector. Once we have on-the-fly error correction our error will be automatically corrected. The correction code is expected to clear the newly introduced EXTENT_DAMAGED flag, making scrub report that error as "corrected" instead of "uncorrectable" eventually. Signed-off-by: Jan Schmidt --- fs/btrfs/extent_io.h | 1 + fs/btrfs/scrub.c | 188 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 183 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index a9dd994bf826..435d454b9926 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -17,6 +17,7 @@ #define EXTENT_NODATASUM (1 << 10) #define EXTENT_DO_ACCOUNTING (1 << 11) #define EXTENT_FIRST_DELALLOC (1 << 12) +#define EXTENT_DAMAGED (1 << 13) #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) #define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 41a01147b959..db09f01c0e4f 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -22,6 +22,7 @@ #include "volumes.h" #include "disk-io.h" #include "ordered-data.h" +#include "transaction.h" #include "backref.h" /* @@ -89,6 +90,7 @@ struct scrub_dev { int first_free; int curr; atomic_t in_flight; + atomic_t fixup_cnt; spinlock_t list_lock; wait_queue_head_t list_wait; u16 csum_size; @@ -102,6 +104,14 @@ struct scrub_dev { spinlock_t stat_lock; }; +struct scrub_fixup_nodatasum { + struct scrub_dev *sdev; + u64 logical; + struct btrfs_root *root; + struct btrfs_work work; + int mirror_num; +}; + struct scrub_warning { struct btrfs_path *path; u64 extent_item_size; @@ -190,12 +200,13 @@ struct scrub_dev *scrub_setup_dev(struct btrfs_device *dev) if (i != SCRUB_BIOS_PER_DEV-1) sdev->bios[i]->next_free = i + 1; - else + else sdev->bios[i]->next_free = -1; } sdev->first_free = 0; sdev->curr = -1; atomic_set(&sdev->in_flight, 0); + atomic_set(&sdev->fixup_cnt, 0); atomic_set(&sdev->cancel_req, 0); sdev->csum_size = btrfs_super_csum_size(&fs_info->super_copy); INIT_LIST_HEAD(&sdev->csum_list); @@ -347,6 +358,151 @@ static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio, kfree(swarn.msg_buf); } +static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx) +{ + struct page *page; + unsigned long index; + struct scrub_fixup_nodatasum *fixup = ctx; + int ret; + int corrected; + struct btrfs_key key; + struct inode *inode; + u64 end = offset + PAGE_SIZE - 1; + struct btrfs_root *local_root; + + key.objectid = root; + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = (u64)-1; + local_root = btrfs_read_fs_root_no_name(fixup->root->fs_info, &key); + if (IS_ERR(local_root)) + return PTR_ERR(local_root); + + key.type = BTRFS_INODE_ITEM_KEY; + key.objectid = inum; + key.offset = 0; + inode = btrfs_iget(fixup->root->fs_info->sb, &key, local_root, NULL); + if (IS_ERR(inode)) + return PTR_ERR(inode); + + ret = set_extent_bit(&BTRFS_I(inode)->io_tree, offset, end, + EXTENT_DAMAGED, 0, NULL, NULL, GFP_NOFS); + + /* set_extent_bit should either succeed or give proper error */ + WARN_ON(ret > 0); + if (ret) + return ret < 0 ? ret : -EFAULT; + + index = offset >> PAGE_CACHE_SHIFT; + + page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); + if (!page) + return -ENOMEM; + + ret = extent_read_full_page(&BTRFS_I(inode)->io_tree, page, + btrfs_get_extent, fixup->mirror_num); + wait_on_page_locked(page); + corrected = !test_range_bit(&BTRFS_I(inode)->io_tree, offset, end, + EXTENT_DAMAGED, 0, NULL); + + if (corrected) + WARN_ON(!PageUptodate(page)); + else + clear_extent_bit(&BTRFS_I(inode)->io_tree, offset, end, + EXTENT_DAMAGED, 0, 0, NULL, GFP_NOFS); + + put_page(page); + iput(inode); + + if (ret < 0) + return ret; + + if (ret == 0 && corrected) { + /* + * we only need to call readpage for one of the inodes belonging + * to this extent. so make iterate_extent_inodes stop + */ + return 1; + } + + return -EIO; +} + +static void scrub_fixup_nodatasum(struct btrfs_work *work) +{ + int ret; + struct scrub_fixup_nodatasum *fixup; + struct scrub_dev *sdev; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_fs_info *fs_info; + struct btrfs_path *path; + int uncorrectable = 0; + + fixup = container_of(work, struct scrub_fixup_nodatasum, work); + sdev = fixup->sdev; + fs_info = fixup->root->fs_info; + + path = btrfs_alloc_path(); + if (!path) { + spin_lock(&sdev->stat_lock); + ++sdev->stat.malloc_errors; + spin_unlock(&sdev->stat_lock); + uncorrectable = 1; + goto out; + } + + trans = btrfs_join_transaction(fixup->root); + if (IS_ERR(trans)) { + uncorrectable = 1; + goto out; + } + + /* + * the idea is to trigger a regular read through the standard path. we + * read a page from the (failed) logical address by specifying the + * corresponding copynum of the failed sector. thus, that readpage is + * expected to fail. + * that is the point where on-the-fly error correction will kick in + * (once it's finished) and rewrite the failed sector if a good copy + * can be found. + */ + ret = iterate_inodes_from_logical(fixup->logical, fixup->root->fs_info, + path, scrub_fixup_readpage, + fixup); + if (ret < 0) { + uncorrectable = 1; + goto out; + } + WARN_ON(ret != 1); + + spin_lock(&sdev->stat_lock); + ++sdev->stat.corrected_errors; + spin_unlock(&sdev->stat_lock); + +out: + if (trans && !IS_ERR(trans)) + btrfs_end_transaction(trans, fixup->root); + if (uncorrectable) { + spin_lock(&sdev->stat_lock); + ++sdev->stat.uncorrectable_errors; + spin_unlock(&sdev->stat_lock); + printk_ratelimited(KERN_ERR "btrfs: unable to fixup " + "(nodatasum) error at logical %llu\n", + fixup->logical); + } + + btrfs_free_path(path); + kfree(fixup); + + /* see caller why we're pretending to be paused in the scrub counters */ + mutex_lock(&fs_info->scrub_lock); + atomic_dec(&fs_info->scrubs_running); + atomic_dec(&fs_info->scrubs_paused); + mutex_unlock(&fs_info->scrub_lock); + atomic_dec(&sdev->fixup_cnt); + wake_up(&fs_info->scrub_pause_wait); + wake_up(&sdev->list_wait); +} + /* * scrub_recheck_error gets called when either verification of the page * failed or the bio failed to read, e.g. with EIO. In the latter case, @@ -417,6 +573,7 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info; struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; struct btrfs_multi_bio *multi = NULL; + struct scrub_fixup_nodatasum *fixup; u64 logical = sbio->logical + ix * PAGE_SIZE; u64 length; int i; @@ -425,12 +582,30 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) if ((sbio->spag[ix].flags & BTRFS_EXTENT_FLAG_DATA) && (sbio->spag[ix].have_csum == 0)) { + fixup = kzalloc(sizeof(*fixup), GFP_NOFS); + if (!fixup) + goto uncorrectable; + fixup->sdev = sdev; + fixup->logical = logical; + fixup->root = fs_info->extent_root; + fixup->mirror_num = sbio->spag[ix].mirror_num; /* - * nodatasum, don't try to fix anything - * FIXME: we can do better, open the inode and trigger a - * writeback + * increment scrubs_running to prevent cancel requests from + * completing as long as a fixup worker is running. we must also + * increment scrubs_paused to prevent deadlocking on pause + * requests used for transactions commits (as the worker uses a + * transaction context). it is safe to regard the fixup worker + * as paused for all matters practical. effectively, we only + * avoid cancellation requests from completing. */ - goto uncorrectable; + mutex_lock(&fs_info->scrub_lock); + atomic_inc(&fs_info->scrubs_running); + atomic_inc(&fs_info->scrubs_paused); + mutex_unlock(&fs_info->scrub_lock); + atomic_inc(&sdev->fixup_cnt); + fixup->work.func = scrub_fixup_nodatasum; + btrfs_queue_worker(&fs_info->scrub_workers, &fixup->work); + return; } length = PAGE_SIZE; @@ -1425,10 +1600,11 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, ret = scrub_enumerate_chunks(sdev, start, end); wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0); - atomic_dec(&fs_info->scrubs_running); wake_up(&fs_info->scrub_pause_wait); + wait_event(sdev->list_wait, atomic_read(&sdev->fixup_cnt) == 0); + if (progress) memcpy(progress, &sdev->stat, sizeof(*progress)); From d7728c960dccf775b92f2c4139f1216275a45c44 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 7 Jul 2011 16:48:38 +0200 Subject: [PATCH 0483/1596] btrfs: new ioctls to do logical->inode and inode->path resolving these ioctls make use of the new functions initially added for scrub. they return all inodes belonging to a logical address (BTRFS_IOC_LOGICAL_INO) and all paths belonging to an inode (BTRFS_IOC_INO_PATHS). Signed-off-by: Jan Schmidt --- fs/btrfs/ioctl.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/ioctl.h | 19 +++++++ 2 files changed, 162 insertions(+) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 538f65a79ec5..7f57efa76d11 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -51,6 +51,7 @@ #include "volumes.h" #include "locking.h" #include "inode-map.h" +#include "backref.h" /* Mask out flags that are inappropriate for the given type of inode. */ static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) @@ -2855,6 +2856,144 @@ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root, return ret; } +static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) +{ + int ret = 0; + int i; + unsigned long rel_ptr; + int size; + struct btrfs_ioctl_ino_path_args *ipa; + struct inode_fs_paths *ipath = NULL; + struct btrfs_path *path; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + ipa = memdup_user(arg, sizeof(*ipa)); + if (IS_ERR(ipa)) { + ret = PTR_ERR(ipa); + ipa = NULL; + goto out; + } + + size = min_t(u32, ipa->size, 4096); + ipath = init_ipath(size, root, path); + if (IS_ERR(ipath)) { + ret = PTR_ERR(ipath); + ipath = NULL; + goto out; + } + + ret = paths_from_inode(ipa->inum, ipath); + if (ret < 0) + goto out; + + for (i = 0; i < ipath->fspath->elem_cnt; ++i) { + rel_ptr = ipath->fspath->str[i] - (char *)ipath->fspath->str; + ipath->fspath->str[i] = (void *)rel_ptr; + } + + ret = copy_to_user(ipa->fspath, ipath->fspath, size); + if (ret) { + ret = -EFAULT; + goto out; + } + +out: + btrfs_free_path(path); + free_ipath(ipath); + kfree(ipa); + + return ret; +} + +static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx) +{ + struct btrfs_data_container *inodes = ctx; + const size_t c = 3 * sizeof(u64); + + if (inodes->bytes_left >= c) { + inodes->bytes_left -= c; + inodes->val[inodes->elem_cnt] = inum; + inodes->val[inodes->elem_cnt + 1] = offset; + inodes->val[inodes->elem_cnt + 2] = root; + inodes->elem_cnt += 3; + } else { + inodes->bytes_missing += c - inodes->bytes_left; + inodes->bytes_left = 0; + inodes->elem_missed += 3; + } + + return 0; +} + +static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, + void __user *arg) +{ + int ret = 0; + int size; + u64 extent_offset; + struct btrfs_ioctl_logical_ino_args *loi; + struct btrfs_data_container *inodes = NULL; + struct btrfs_path *path = NULL; + struct btrfs_key key; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + loi = memdup_user(arg, sizeof(*loi)); + if (IS_ERR(loi)) { + ret = PTR_ERR(loi); + loi = NULL; + goto out; + } + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + size = min_t(u32, loi->size, 4096); + inodes = init_data_container(size); + if (IS_ERR(inodes)) { + ret = PTR_ERR(inodes); + inodes = NULL; + goto out; + } + + ret = extent_from_logical(root->fs_info, loi->logical, path, &key); + + if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) + ret = -ENOENT; + if (ret < 0) + goto out; + + extent_offset = loi->logical - key.objectid; + ret = iterate_extent_inodes(root->fs_info, path, key.objectid, + extent_offset, build_ino_list, inodes); + + if (ret < 0) + goto out; + + ret = copy_to_user(loi->inodes, inodes, size); + if (ret) + ret = -EFAULT; + +out: + btrfs_free_path(path); + kfree(inodes); + kfree(loi); + + return ret; +} + long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2912,6 +3051,10 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_tree_search(file, argp); case BTRFS_IOC_INO_LOOKUP: return btrfs_ioctl_ino_lookup(file, argp); + case BTRFS_IOC_INO_PATHS: + return btrfs_ioctl_ino_to_path(root, argp); + case BTRFS_IOC_LOGICAL_INO: + return btrfs_ioctl_logical_to_ino(root, argp); case BTRFS_IOC_SPACE_INFO: return btrfs_ioctl_space_info(root, argp); case BTRFS_IOC_SYNC: diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 1857e3871843..2da30d4950e6 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h @@ -204,6 +204,20 @@ struct btrfs_data_container { }; }; +struct btrfs_ioctl_ino_path_args { + __u64 inum; /* in */ + __u32 size; /* in */ + __u64 reserved[4]; + struct btrfs_data_container *fspath; /* out */ +}; + +struct btrfs_ioctl_logical_ino_args { + __u64 logical; /* in */ + __u32 size; /* in */ + __u64 reserved[4]; + struct btrfs_data_container *inodes; /* out */ +}; + #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ @@ -259,4 +273,9 @@ struct btrfs_data_container { struct btrfs_ioctl_dev_info_args) #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ struct btrfs_ioctl_fs_info_args) +#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \ + struct btrfs_ioctl_ino_path_args) +#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ + struct btrfs_ioctl_ino_path_args) + #endif From a1d3c4786a4b9c71c0767aa656a759968f7554b6 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 4 Aug 2011 17:15:33 +0200 Subject: [PATCH 0484/1596] btrfs: btrfs_multi_bio replaced with btrfs_bio btrfs_bio is a bio abstraction able to split and not complete after the last bio has returned (like the old btrfs_multi_bio). Additionally, btrfs_bio tracks the mirror_num used to read data which can be used for error correction purposes. Signed-off-by: Jan Schmidt --- fs/btrfs/extent-tree.c | 10 ++-- fs/btrfs/scrub.c | 20 +++---- fs/btrfs/volumes.c | 128 ++++++++++++++++++++++------------------- fs/btrfs/volumes.h | 10 +++- 4 files changed, 90 insertions(+), 78 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index f5be06a2462f..119f842c1d4f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1770,18 +1770,18 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, { int ret; u64 discarded_bytes = 0; - struct btrfs_multi_bio *multi = NULL; + struct btrfs_bio *bbio = NULL; /* Tell the block device(s) that the sectors can be discarded */ ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD, - bytenr, &num_bytes, &multi, 0); + bytenr, &num_bytes, &bbio, 0); if (!ret) { - struct btrfs_bio_stripe *stripe = multi->stripes; + struct btrfs_bio_stripe *stripe = bbio->stripes; int i; - for (i = 0; i < multi->num_stripes; i++, stripe++) { + for (i = 0; i < bbio->num_stripes; i++, stripe++) { if (!stripe->dev->can_discard) continue; @@ -1800,7 +1800,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, */ ret = 0; } - kfree(multi); + kfree(bbio); } if (actual_bytes) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index db09f01c0e4f..97142a218f0a 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -572,7 +572,7 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) struct scrub_dev *sdev = sbio->sdev; struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info; struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; - struct btrfs_multi_bio *multi = NULL; + struct btrfs_bio *bbio = NULL; struct scrub_fixup_nodatasum *fixup; u64 logical = sbio->logical + ix * PAGE_SIZE; u64 length; @@ -610,8 +610,8 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) length = PAGE_SIZE; ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length, - &multi, 0); - if (ret || !multi || length < PAGE_SIZE) { + &bbio, 0); + if (ret || !bbio || length < PAGE_SIZE) { printk(KERN_ERR "scrub_fixup: btrfs_map_block failed us for %llu\n", (unsigned long long)logical); @@ -619,19 +619,19 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) return; } - if (multi->num_stripes == 1) + if (bbio->num_stripes == 1) /* there aren't any replicas */ goto uncorrectable; /* * first find a good copy */ - for (i = 0; i < multi->num_stripes; ++i) { + for (i = 0; i < bbio->num_stripes; ++i) { if (i + 1 == sbio->spag[ix].mirror_num) continue; - if (scrub_fixup_io(READ, multi->stripes[i].dev->bdev, - multi->stripes[i].physical >> 9, + if (scrub_fixup_io(READ, bbio->stripes[i].dev->bdev, + bbio->stripes[i].physical >> 9, sbio->bio->bi_io_vec[ix].bv_page)) { /* I/O-error, this is not a good copy */ continue; @@ -640,7 +640,7 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) if (scrub_fixup_check(sbio, ix) == 0) break; } - if (i == multi->num_stripes) + if (i == bbio->num_stripes) goto uncorrectable; if (!sdev->readonly) { @@ -655,7 +655,7 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) } } - kfree(multi); + kfree(bbio); spin_lock(&sdev->stat_lock); ++sdev->stat.corrected_errors; spin_unlock(&sdev->stat_lock); @@ -665,7 +665,7 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) return; uncorrectable: - kfree(multi); + kfree(bbio); spin_lock(&sdev->stat_lock); ++sdev->stat.uncorrectable_errors; spin_unlock(&sdev->stat_lock); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f2a4cc79da61..9db4d7962f9b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2848,7 +2848,7 @@ static int find_live_mirror(struct map_lookup *map, int first, int num, static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, - struct btrfs_multi_bio **multi_ret, + struct btrfs_bio **bbio_ret, int mirror_num) { struct extent_map *em; @@ -2866,18 +2866,18 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, int i; int num_stripes; int max_errors = 0; - struct btrfs_multi_bio *multi = NULL; + struct btrfs_bio *bbio = NULL; - if (multi_ret && !(rw & (REQ_WRITE | REQ_DISCARD))) + if (bbio_ret && !(rw & (REQ_WRITE | REQ_DISCARD))) stripes_allocated = 1; again: - if (multi_ret) { - multi = kzalloc(btrfs_multi_bio_size(stripes_allocated), + if (bbio_ret) { + bbio = kzalloc(btrfs_bio_size(stripes_allocated), GFP_NOFS); - if (!multi) + if (!bbio) return -ENOMEM; - atomic_set(&multi->error, 0); + atomic_set(&bbio->error, 0); } read_lock(&em_tree->lock); @@ -2898,7 +2898,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, if (mirror_num > map->num_stripes) mirror_num = 0; - /* if our multi bio struct is too small, back off and try again */ + /* if our btrfs_bio struct is too small, back off and try again */ if (rw & REQ_WRITE) { if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) { @@ -2917,11 +2917,11 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, stripes_required = map->num_stripes; } } - if (multi_ret && (rw & (REQ_WRITE | REQ_DISCARD)) && + if (bbio_ret && (rw & (REQ_WRITE | REQ_DISCARD)) && stripes_allocated < stripes_required) { stripes_allocated = map->num_stripes; free_extent_map(em); - kfree(multi); + kfree(bbio); goto again; } stripe_nr = offset; @@ -2950,7 +2950,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, *length = em->len - offset; } - if (!multi_ret) + if (!bbio_ret) goto out; num_stripes = 1; @@ -2975,13 +2975,17 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, stripe_index = find_live_mirror(map, 0, map->num_stripes, current->pid % map->num_stripes); + mirror_num = stripe_index + 1; } } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { - if (rw & (REQ_WRITE | REQ_DISCARD)) + if (rw & (REQ_WRITE | REQ_DISCARD)) { num_stripes = map->num_stripes; - else if (mirror_num) + } else if (mirror_num) { stripe_index = mirror_num - 1; + } else { + mirror_num = 1; + } } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { int factor = map->num_stripes / map->sub_stripes; @@ -3001,6 +3005,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, stripe_index = find_live_mirror(map, stripe_index, map->sub_stripes, stripe_index + current->pid % map->sub_stripes); + mirror_num = stripe_index + 1; } } else { /* @@ -3009,15 +3014,16 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, * stripe_index is the number of our device in the stripe array */ stripe_index = do_div(stripe_nr, map->num_stripes); + mirror_num = stripe_index + 1; } BUG_ON(stripe_index >= map->num_stripes); if (rw & REQ_DISCARD) { for (i = 0; i < num_stripes; i++) { - multi->stripes[i].physical = + bbio->stripes[i].physical = map->stripes[stripe_index].physical + stripe_offset + stripe_nr * map->stripe_len; - multi->stripes[i].dev = map->stripes[stripe_index].dev; + bbio->stripes[i].dev = map->stripes[stripe_index].dev; if (map->type & BTRFS_BLOCK_GROUP_RAID0) { u64 stripes; @@ -3038,16 +3044,16 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, } stripes = stripe_nr_end - 1 - j; do_div(stripes, map->num_stripes); - multi->stripes[i].length = map->stripe_len * + bbio->stripes[i].length = map->stripe_len * (stripes - stripe_nr + 1); if (i == 0) { - multi->stripes[i].length -= + bbio->stripes[i].length -= stripe_offset; stripe_offset = 0; } if (stripe_index == last_stripe) - multi->stripes[i].length -= + bbio->stripes[i].length -= stripe_end_offset; } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { u64 stripes; @@ -3072,11 +3078,11 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, } stripes = stripe_nr_end - 1 - j; do_div(stripes, factor); - multi->stripes[i].length = map->stripe_len * + bbio->stripes[i].length = map->stripe_len * (stripes - stripe_nr + 1); if (i < map->sub_stripes) { - multi->stripes[i].length -= + bbio->stripes[i].length -= stripe_offset; if (i == map->sub_stripes - 1) stripe_offset = 0; @@ -3084,11 +3090,11 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, if (stripe_index >= last_stripe && stripe_index <= (last_stripe + map->sub_stripes - 1)) { - multi->stripes[i].length -= + bbio->stripes[i].length -= stripe_end_offset; } } else - multi->stripes[i].length = *length; + bbio->stripes[i].length = *length; stripe_index++; if (stripe_index == map->num_stripes) { @@ -3099,19 +3105,20 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, } } else { for (i = 0; i < num_stripes; i++) { - multi->stripes[i].physical = + bbio->stripes[i].physical = map->stripes[stripe_index].physical + stripe_offset + stripe_nr * map->stripe_len; - multi->stripes[i].dev = + bbio->stripes[i].dev = map->stripes[stripe_index].dev; stripe_index++; } } - if (multi_ret) { - *multi_ret = multi; - multi->num_stripes = num_stripes; - multi->max_errors = max_errors; + if (bbio_ret) { + *bbio_ret = bbio; + bbio->num_stripes = num_stripes; + bbio->max_errors = max_errors; + bbio->mirror_num = mirror_num; } out: free_extent_map(em); @@ -3120,9 +3127,9 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, - struct btrfs_multi_bio **multi_ret, int mirror_num) + struct btrfs_bio **bbio_ret, int mirror_num) { - return __btrfs_map_block(map_tree, rw, logical, length, multi_ret, + return __btrfs_map_block(map_tree, rw, logical, length, bbio_ret, mirror_num); } @@ -3191,28 +3198,28 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, return 0; } -static void end_bio_multi_stripe(struct bio *bio, int err) +static void btrfs_end_bio(struct bio *bio, int err) { - struct btrfs_multi_bio *multi = bio->bi_private; + struct btrfs_bio *bbio = bio->bi_private; int is_orig_bio = 0; if (err) - atomic_inc(&multi->error); + atomic_inc(&bbio->error); - if (bio == multi->orig_bio) + if (bio == bbio->orig_bio) is_orig_bio = 1; - if (atomic_dec_and_test(&multi->stripes_pending)) { + if (atomic_dec_and_test(&bbio->stripes_pending)) { if (!is_orig_bio) { bio_put(bio); - bio = multi->orig_bio; + bio = bbio->orig_bio; } - bio->bi_private = multi->private; - bio->bi_end_io = multi->end_io; + bio->bi_private = bbio->private; + bio->bi_end_io = bbio->end_io; /* only send an error to the higher layers if it is * beyond the tolerance of the multi-bio */ - if (atomic_read(&multi->error) > multi->max_errors) { + if (atomic_read(&bbio->error) > bbio->max_errors) { err = -EIO; } else if (err) { /* @@ -3222,7 +3229,7 @@ static void end_bio_multi_stripe(struct bio *bio, int err) set_bit(BIO_UPTODATE, &bio->bi_flags); err = 0; } - kfree(multi); + kfree(bbio); bio_endio(bio, err); } else if (!is_orig_bio) { @@ -3302,20 +3309,20 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, u64 logical = (u64)bio->bi_sector << 9; u64 length = 0; u64 map_length; - struct btrfs_multi_bio *multi = NULL; int ret; int dev_nr = 0; int total_devs = 1; + struct btrfs_bio *bbio = NULL; length = bio->bi_size; map_tree = &root->fs_info->mapping_tree; map_length = length; - ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi, + ret = btrfs_map_block(map_tree, rw, logical, &map_length, &bbio, mirror_num); BUG_ON(ret); - total_devs = multi->num_stripes; + total_devs = bbio->num_stripes; if (map_length < length) { printk(KERN_CRIT "mapping failed logical %llu bio len %llu " "len %llu\n", (unsigned long long)logical, @@ -3323,25 +3330,28 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, (unsigned long long)map_length); BUG(); } - multi->end_io = first_bio->bi_end_io; - multi->private = first_bio->bi_private; - multi->orig_bio = first_bio; - atomic_set(&multi->stripes_pending, multi->num_stripes); + + bbio->orig_bio = first_bio; + bbio->private = first_bio->bi_private; + bbio->end_io = first_bio->bi_end_io; + atomic_set(&bbio->stripes_pending, bbio->num_stripes); while (dev_nr < total_devs) { - if (total_devs > 1) { - if (dev_nr < total_devs - 1) { - bio = bio_clone(first_bio, GFP_NOFS); - BUG_ON(!bio); - } else { - bio = first_bio; - } - bio->bi_private = multi; - bio->bi_end_io = end_bio_multi_stripe; + if (dev_nr < total_devs - 1) { + bio = bio_clone(first_bio, GFP_NOFS); + BUG_ON(!bio); + } else { + bio = first_bio; } - bio->bi_sector = multi->stripes[dev_nr].physical >> 9; - dev = multi->stripes[dev_nr].dev; + bio->bi_private = bbio; + bio->bi_end_io = btrfs_end_bio; + bio->bi_sector = bbio->stripes[dev_nr].physical >> 9; + dev = bbio->stripes[dev_nr].dev; if (dev && dev->bdev && (rw != WRITE || dev->writeable)) { + pr_debug("btrfs_map_bio: rw %d, secor=%llu, dev=%lu " + "(%s id %llu), size=%u\n", rw, + (u64)bio->bi_sector, (u_long)dev->bdev->bd_dev, + dev->name, dev->devid, bio->bi_size); bio->bi_bdev = dev->bdev; if (async_submit) schedule_bio(root, dev, rw, bio); @@ -3354,8 +3364,6 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, } dev_nr++; } - if (total_devs == 1) - kfree(multi); return 0; } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 6d866db4e177..71f4f3f67495 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -136,7 +136,10 @@ struct btrfs_bio_stripe { u64 length; /* only used for discard mappings */ }; -struct btrfs_multi_bio { +struct btrfs_bio; +typedef void (btrfs_bio_end_io_t) (struct btrfs_bio *bio, int err); + +struct btrfs_bio { atomic_t stripes_pending; bio_end_io_t *end_io; struct bio *orig_bio; @@ -144,6 +147,7 @@ struct btrfs_multi_bio { atomic_t error; int max_errors; int num_stripes; + int mirror_num; struct btrfs_bio_stripe stripes[]; }; @@ -171,7 +175,7 @@ struct map_lookup { int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, u64 end, u64 *length); -#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \ +#define btrfs_bio_size(n) (sizeof(struct btrfs_bio) + \ (sizeof(struct btrfs_bio_stripe) * (n))) int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, @@ -180,7 +184,7 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, u64 chunk_offset, u64 start, u64 num_bytes); int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, - struct btrfs_multi_bio **multi_ret, int mirror_num); + struct btrfs_bio **bbio_ret, int mirror_num); int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, u64 chunk_start, u64 physical, u64 devid, u64 **logical, int *naddrs, int *stripe_len); From 1503140d3ec2be9b917d2f8f7c64cb77b79a215b Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 16 Jun 2011 14:37:03 +0200 Subject: [PATCH 0485/1596] btrfs: Do not use bio->bi_bdev after submission The block layer modifies bio->bi_bdev and bio->bi_sector while working on the bio, they do _not_ come back unmodified in the completion callback. To call add_page, we need at least some bi_bdev set, which is why the code was working, previously. With this patch, we use the latest_bdev from fsinfo instead of the leftover in the bio. This gives us the possibility to use the bi_bdev field for another purpose. Signed-off-by: Jan Schmidt --- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index efee8c7cfa45..936a6fabaa9f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1915,7 +1915,7 @@ static int btrfs_io_failed_hook(struct bio *failed_bio, bio->bi_private = state; bio->bi_end_io = failed_bio->bi_end_io; bio->bi_sector = failrec->logical >> 9; - bio->bi_bdev = failed_bio->bi_bdev; + bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; bio->bi_size = 0; bio_add_page(bio, page, failrec->len, start - page_offset(page)); From 2774b2ca3d49124bf1ae89e8d575b3dab4221266 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 16 Jun 2011 12:05:19 +0200 Subject: [PATCH 0486/1596] btrfs: Put mirror_num in bi_bdev The error correction code wants to make sure that only the bad mirror is rewritten. Thus, we need to know which mirror is the bad one. I did not find a more apropriate field than bi_bdev. But I think using this is fine, because it is modified by the block layer, anyway, and should not be read after the bio returned. Signed-off-by: Jan Schmidt --- fs/btrfs/volumes.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 9db4d7962f9b..18baac5a3f6c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3216,6 +3216,8 @@ static void btrfs_end_bio(struct bio *bio, int err) } bio->bi_private = bbio->private; bio->bi_end_io = bbio->end_io; + bio->bi_bdev = (struct block_device *) + (unsigned long)bbio->mirror_num; /* only send an error to the higher layers if it is * beyond the tolerance of the multi-bio */ From 4a54c8c165b66300830a67349fc7595e3fc442f7 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 22 Jul 2011 15:41:52 +0200 Subject: [PATCH 0487/1596] btrfs: Moved repair code from inode.c to extent_io.c The raid-retry code in inode.c can be generalized so that it works for metadata as well. Thus, this patch moves it to extent_io.c and makes the raid-retry code a raid-repair code. Repair works that way: Whenever a read error occurs and we have more mirrors to try, note the failed mirror, and retry another. If we find a good one, check if we did note a failure earlier and if so, do not allow the read to complete until after the bad sector was written with the good data we just fetched. As we have the extent locked while reading, no one can change the data in between. Signed-off-by: Jan Schmidt --- fs/btrfs/extent_io.c | 387 ++++++++++++++++++++++++++++++++++++++++++- fs/btrfs/extent_io.h | 10 +- fs/btrfs/inode.c | 155 +---------------- 3 files changed, 393 insertions(+), 159 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index afebb95e3490..624ef10d36cc 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -17,6 +17,7 @@ #include "compat.h" #include "ctree.h" #include "btrfs_inode.h" +#include "volumes.h" static struct kmem_cache *extent_state_cache; static struct kmem_cache *extent_buffer_cache; @@ -1599,6 +1600,368 @@ static int check_page_writeback(struct extent_io_tree *tree, return 0; } +/* + * When IO fails, either with EIO or csum verification fails, we + * try other mirrors that might have a good copy of the data. This + * io_failure_record is used to record state as we go through all the + * mirrors. If another mirror has good data, the page is set up to date + * and things continue. If a good mirror can't be found, the original + * bio end_io callback is called to indicate things have failed. + */ +struct io_failure_record { + struct page *page; + u64 start; + u64 len; + u64 logical; + unsigned long bio_flags; + int this_mirror; + int failed_mirror; + int in_validation; +}; + +static int free_io_failure(struct inode *inode, struct io_failure_record *rec, + int did_repair) +{ + int ret; + int err = 0; + struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree; + + set_state_private(failure_tree, rec->start, 0); + ret = clear_extent_bits(failure_tree, rec->start, + rec->start + rec->len - 1, + EXTENT_LOCKED | EXTENT_DIRTY, GFP_NOFS); + if (ret) + err = ret; + + if (did_repair) { + ret = clear_extent_bits(&BTRFS_I(inode)->io_tree, rec->start, + rec->start + rec->len - 1, + EXTENT_DAMAGED, GFP_NOFS); + if (ret && !err) + err = ret; + } + + kfree(rec); + return err; +} + +static void repair_io_failure_callback(struct bio *bio, int err) +{ + complete(bio->bi_private); +} + +/* + * this bypasses the standard btrfs submit functions deliberately, as + * the standard behavior is to write all copies in a raid setup. here we only + * want to write the one bad copy. so we do the mapping for ourselves and issue + * submit_bio directly. + * to avoid any synchonization issues, wait for the data after writing, which + * actually prevents the read that triggered the error from finishing. + * currently, there can be no more than two copies of every data bit. thus, + * exactly one rewrite is required. + */ +int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start, + u64 length, u64 logical, struct page *page, + int mirror_num) +{ + struct bio *bio; + struct btrfs_device *dev; + DECLARE_COMPLETION_ONSTACK(compl); + u64 map_length = 0; + u64 sector; + struct btrfs_bio *bbio = NULL; + int ret; + + BUG_ON(!mirror_num); + + bio = bio_alloc(GFP_NOFS, 1); + if (!bio) + return -EIO; + bio->bi_private = &compl; + bio->bi_end_io = repair_io_failure_callback; + bio->bi_size = 0; + map_length = length; + + ret = btrfs_map_block(map_tree, WRITE, logical, + &map_length, &bbio, mirror_num); + if (ret) { + bio_put(bio); + return -EIO; + } + BUG_ON(mirror_num != bbio->mirror_num); + sector = bbio->stripes[mirror_num-1].physical >> 9; + bio->bi_sector = sector; + dev = bbio->stripes[mirror_num-1].dev; + kfree(bbio); + if (!dev || !dev->bdev || !dev->writeable) { + bio_put(bio); + return -EIO; + } + bio->bi_bdev = dev->bdev; + bio_add_page(bio, page, length, start-page_offset(page)); + submit_bio(WRITE_SYNC, bio); + wait_for_completion(&compl); + + if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { + /* try to remap that extent elsewhere? */ + bio_put(bio); + return -EIO; + } + + printk(KERN_INFO "btrfs read error corrected: ino %lu off %llu (dev %s " + "sector %llu)\n", page->mapping->host->i_ino, start, + dev->name, sector); + + bio_put(bio); + return 0; +} + +/* + * each time an IO finishes, we do a fast check in the IO failure tree + * to see if we need to process or clean up an io_failure_record + */ +static int clean_io_failure(u64 start, struct page *page) +{ + u64 private; + u64 private_failure; + struct io_failure_record *failrec; + struct btrfs_mapping_tree *map_tree; + struct extent_state *state; + int num_copies; + int did_repair = 0; + int ret; + struct inode *inode = page->mapping->host; + + private = 0; + ret = count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private, + (u64)-1, 1, EXTENT_DIRTY, 0); + if (!ret) + return 0; + + ret = get_state_private(&BTRFS_I(inode)->io_failure_tree, start, + &private_failure); + if (ret) + return 0; + + failrec = (struct io_failure_record *)(unsigned long) private_failure; + BUG_ON(!failrec->this_mirror); + + if (failrec->in_validation) { + /* there was no real error, just free the record */ + pr_debug("clean_io_failure: freeing dummy error at %llu\n", + failrec->start); + did_repair = 1; + goto out; + } + + spin_lock(&BTRFS_I(inode)->io_tree.lock); + state = find_first_extent_bit_state(&BTRFS_I(inode)->io_tree, + failrec->start, + EXTENT_LOCKED); + spin_unlock(&BTRFS_I(inode)->io_tree.lock); + + if (state && state->start == failrec->start) { + map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree; + num_copies = btrfs_num_copies(map_tree, failrec->logical, + failrec->len); + if (num_copies > 1) { + ret = repair_io_failure(map_tree, start, failrec->len, + failrec->logical, page, + failrec->failed_mirror); + did_repair = !ret; + } + } + +out: + if (!ret) + ret = free_io_failure(inode, failrec, did_repair); + + return ret; +} + +/* + * this is a generic handler for readpage errors (default + * readpage_io_failed_hook). if other copies exist, read those and write back + * good data to the failed position. does not investigate in remapping the + * failed extent elsewhere, hoping the device will be smart enough to do this as + * needed + */ + +static int bio_readpage_error(struct bio *failed_bio, struct page *page, + u64 start, u64 end, int failed_mirror, + struct extent_state *state) +{ + struct io_failure_record *failrec = NULL; + u64 private; + struct extent_map *em; + struct inode *inode = page->mapping->host; + struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree; + struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree; + struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; + struct bio *bio; + int num_copies; + int ret; + int read_mode; + u64 logical; + + BUG_ON(failed_bio->bi_rw & REQ_WRITE); + + ret = get_state_private(failure_tree, start, &private); + if (ret) { + failrec = kzalloc(sizeof(*failrec), GFP_NOFS); + if (!failrec) + return -ENOMEM; + failrec->start = start; + failrec->len = end - start + 1; + failrec->this_mirror = 0; + failrec->bio_flags = 0; + failrec->in_validation = 0; + + read_lock(&em_tree->lock); + em = lookup_extent_mapping(em_tree, start, failrec->len); + if (!em) { + read_unlock(&em_tree->lock); + kfree(failrec); + return -EIO; + } + + if (em->start > start || em->start + em->len < start) { + free_extent_map(em); + em = NULL; + } + read_unlock(&em_tree->lock); + + if (!em || IS_ERR(em)) { + kfree(failrec); + return -EIO; + } + logical = start - em->start; + logical = em->block_start + logical; + if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { + logical = em->block_start; + failrec->bio_flags = EXTENT_BIO_COMPRESSED; + extent_set_compress_type(&failrec->bio_flags, + em->compress_type); + } + pr_debug("bio_readpage_error: (new) logical=%llu, start=%llu, " + "len=%llu\n", logical, start, failrec->len); + failrec->logical = logical; + free_extent_map(em); + + /* set the bits in the private failure tree */ + ret = set_extent_bits(failure_tree, start, end, + EXTENT_LOCKED | EXTENT_DIRTY, GFP_NOFS); + if (ret >= 0) + ret = set_state_private(failure_tree, start, + (u64)(unsigned long)failrec); + /* set the bits in the inode's tree */ + if (ret >= 0) + ret = set_extent_bits(tree, start, end, EXTENT_DAMAGED, + GFP_NOFS); + if (ret < 0) { + kfree(failrec); + return ret; + } + } else { + failrec = (struct io_failure_record *)(unsigned long)private; + pr_debug("bio_readpage_error: (found) logical=%llu, " + "start=%llu, len=%llu, validation=%d\n", + failrec->logical, failrec->start, failrec->len, + failrec->in_validation); + /* + * when data can be on disk more than twice, add to failrec here + * (e.g. with a list for failed_mirror) to make + * clean_io_failure() clean all those errors at once. + */ + } + num_copies = btrfs_num_copies( + &BTRFS_I(inode)->root->fs_info->mapping_tree, + failrec->logical, failrec->len); + if (num_copies == 1) { + /* + * we only have a single copy of the data, so don't bother with + * all the retry and error correction code that follows. no + * matter what the error is, it is very likely to persist. + */ + pr_debug("bio_readpage_error: cannot repair, num_copies == 1. " + "state=%p, num_copies=%d, next_mirror %d, " + "failed_mirror %d\n", state, num_copies, + failrec->this_mirror, failed_mirror); + free_io_failure(inode, failrec, 0); + return -EIO; + } + + if (!state) { + spin_lock(&tree->lock); + state = find_first_extent_bit_state(tree, failrec->start, + EXTENT_LOCKED); + if (state && state->start != failrec->start) + state = NULL; + spin_unlock(&tree->lock); + } + + /* + * there are two premises: + * a) deliver good data to the caller + * b) correct the bad sectors on disk + */ + if (failed_bio->bi_vcnt > 1) { + /* + * to fulfill b), we need to know the exact failing sectors, as + * we don't want to rewrite any more than the failed ones. thus, + * we need separate read requests for the failed bio + * + * if the following BUG_ON triggers, our validation request got + * merged. we need separate requests for our algorithm to work. + */ + BUG_ON(failrec->in_validation); + failrec->in_validation = 1; + failrec->this_mirror = failed_mirror; + read_mode = READ_SYNC | REQ_FAILFAST_DEV; + } else { + /* + * we're ready to fulfill a) and b) alongside. get a good copy + * of the failed sector and if we succeed, we have setup + * everything for repair_io_failure to do the rest for us. + */ + if (failrec->in_validation) { + BUG_ON(failrec->this_mirror != failed_mirror); + failrec->in_validation = 0; + failrec->this_mirror = 0; + } + failrec->failed_mirror = failed_mirror; + failrec->this_mirror++; + if (failrec->this_mirror == failed_mirror) + failrec->this_mirror++; + read_mode = READ_SYNC; + } + + if (!state || failrec->this_mirror > num_copies) { + pr_debug("bio_readpage_error: (fail) state=%p, num_copies=%d, " + "next_mirror %d, failed_mirror %d\n", state, + num_copies, failrec->this_mirror, failed_mirror); + free_io_failure(inode, failrec, 0); + return -EIO; + } + + bio = bio_alloc(GFP_NOFS, 1); + bio->bi_private = state; + bio->bi_end_io = failed_bio->bi_end_io; + bio->bi_sector = failrec->logical >> 9; + bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; + bio->bi_size = 0; + + bio_add_page(bio, page, failrec->len, start - page_offset(page)); + + pr_debug("bio_readpage_error: submitting new read[%#x] to " + "this_mirror=%d, num_copies=%d, in_validation=%d\n", read_mode, + failrec->this_mirror, num_copies, failrec->in_validation); + + tree->ops->submit_bio_hook(inode, read_mode, bio, failrec->this_mirror, + failrec->bio_flags, 0); + return 0; +} + /* lots and lots of room for performance fixes in the end_bio funcs */ /* @@ -1697,6 +2060,9 @@ static void end_bio_extent_readpage(struct bio *bio, int err) struct extent_state *cached = NULL; struct extent_state *state; + pr_debug("end_bio_extent_readpage: bi_vcnt=%d, idx=%d, err=%d, " + "mirror=%ld\n", bio->bi_vcnt, bio->bi_idx, err, + (long int)bio->bi_bdev); tree = &BTRFS_I(page->mapping->host)->io_tree; start = ((u64)page->index << PAGE_CACHE_SHIFT) + @@ -1727,11 +2093,19 @@ static void end_bio_extent_readpage(struct bio *bio, int err) state); if (ret) uptodate = 0; + else + clean_io_failure(start, page); } - if (!uptodate && tree->ops && - tree->ops->readpage_io_failed_hook) { - ret = tree->ops->readpage_io_failed_hook(bio, page, - start, end, NULL); + if (!uptodate) { + u64 failed_mirror; + failed_mirror = (u64)bio->bi_bdev; + if (tree->ops && tree->ops->readpage_io_failed_hook) + ret = tree->ops->readpage_io_failed_hook( + bio, page, start, end, + failed_mirror, NULL); + else + ret = bio_readpage_error(bio, page, start, end, + failed_mirror, NULL); if (ret == 0) { uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); @@ -1811,6 +2185,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num, mirror_num, bio_flags, start); else submit_bio(rw, bio); + if (bio_flagged(bio, BIO_EOPNOTSUPP)) ret = -EOPNOTSUPP; bio_put(bio); @@ -2926,7 +3301,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, return ret; } -static inline struct page *extent_buffer_page(struct extent_buffer *eb, +inline struct page *extent_buffer_page(struct extent_buffer *eb, unsigned long i) { struct page *p; @@ -2951,7 +3326,7 @@ static inline struct page *extent_buffer_page(struct extent_buffer *eb, return p; } -static inline unsigned long num_extent_pages(u64 start, u64 len) +inline unsigned long num_extent_pages(u64 start, u64 len) { return ((start + len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) - (start >> PAGE_CACHE_SHIFT); diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 435d454b9926..a8e20b672922 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -68,7 +68,7 @@ struct extent_io_ops { unsigned long bio_flags); int (*readpage_io_hook)(struct page *page, u64 start, u64 end); int (*readpage_io_failed_hook)(struct bio *bio, struct page *page, - u64 start, u64 end, + u64 start, u64 end, u64 failed_mirror, struct extent_state *state); int (*writepage_io_failed_hook)(struct bio *bio, struct page *page, u64 start, u64 end, @@ -252,6 +252,8 @@ void free_extent_buffer(struct extent_buffer *eb); int read_extent_buffer_pages(struct extent_io_tree *tree, struct extent_buffer *eb, u64 start, int wait, get_extent_t *get_extent, int mirror_num); +unsigned long num_extent_pages(u64 start, u64 len); +struct page *extent_buffer_page(struct extent_buffer *eb, unsigned long i); static inline void extent_buffer_get(struct extent_buffer *eb) { @@ -301,4 +303,10 @@ int extent_clear_unlock_delalloc(struct inode *inode, struct bio * btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, gfp_t gfp_flags); + +struct btrfs_mapping_tree; + +int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start, + u64 length, u64 logical, struct page *page, + int mirror_num); #endif diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 936a6fabaa9f..9327f45434e8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -45,10 +45,10 @@ #include "btrfs_inode.h" #include "ioctl.h" #include "print-tree.h" -#include "volumes.h" #include "ordered-data.h" #include "xattr.h" #include "tree-log.h" +#include "volumes.h" #include "compression.h" #include "locking.h" #include "free-space-cache.h" @@ -1818,154 +1818,10 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, return btrfs_finish_ordered_io(page->mapping->host, start, end); } -/* - * When IO fails, either with EIO or csum verification fails, we - * try other mirrors that might have a good copy of the data. This - * io_failure_record is used to record state as we go through all the - * mirrors. If another mirror has good data, the page is set up to date - * and things continue. If a good mirror can't be found, the original - * bio end_io callback is called to indicate things have failed. - */ -struct io_failure_record { - struct page *page; - u64 start; - u64 len; - u64 logical; - unsigned long bio_flags; - int last_mirror; -}; - -static int btrfs_io_failed_hook(struct bio *failed_bio, - struct page *page, u64 start, u64 end, - struct extent_state *state) -{ - struct io_failure_record *failrec = NULL; - u64 private; - struct extent_map *em; - struct inode *inode = page->mapping->host; - struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct bio *bio; - int num_copies; - int ret; - int rw; - u64 logical; - - ret = get_state_private(failure_tree, start, &private); - if (ret) { - failrec = kmalloc(sizeof(*failrec), GFP_NOFS); - if (!failrec) - return -ENOMEM; - failrec->start = start; - failrec->len = end - start + 1; - failrec->last_mirror = 0; - failrec->bio_flags = 0; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, start, failrec->len); - if (em->start > start || em->start + em->len < start) { - free_extent_map(em); - em = NULL; - } - read_unlock(&em_tree->lock); - - if (IS_ERR_OR_NULL(em)) { - kfree(failrec); - return -EIO; - } - logical = start - em->start; - logical = em->block_start + logical; - if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { - logical = em->block_start; - failrec->bio_flags = EXTENT_BIO_COMPRESSED; - extent_set_compress_type(&failrec->bio_flags, - em->compress_type); - } - failrec->logical = logical; - free_extent_map(em); - set_extent_bits(failure_tree, start, end, EXTENT_LOCKED | - EXTENT_DIRTY, GFP_NOFS); - set_state_private(failure_tree, start, - (u64)(unsigned long)failrec); - } else { - failrec = (struct io_failure_record *)(unsigned long)private; - } - num_copies = btrfs_num_copies( - &BTRFS_I(inode)->root->fs_info->mapping_tree, - failrec->logical, failrec->len); - failrec->last_mirror++; - if (!state) { - spin_lock(&BTRFS_I(inode)->io_tree.lock); - state = find_first_extent_bit_state(&BTRFS_I(inode)->io_tree, - failrec->start, - EXTENT_LOCKED); - if (state && state->start != failrec->start) - state = NULL; - spin_unlock(&BTRFS_I(inode)->io_tree.lock); - } - if (!state || failrec->last_mirror > num_copies) { - set_state_private(failure_tree, failrec->start, 0); - clear_extent_bits(failure_tree, failrec->start, - failrec->start + failrec->len - 1, - EXTENT_LOCKED | EXTENT_DIRTY, GFP_NOFS); - kfree(failrec); - return -EIO; - } - bio = bio_alloc(GFP_NOFS, 1); - bio->bi_private = state; - bio->bi_end_io = failed_bio->bi_end_io; - bio->bi_sector = failrec->logical >> 9; - bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; - bio->bi_size = 0; - - bio_add_page(bio, page, failrec->len, start - page_offset(page)); - if (failed_bio->bi_rw & REQ_WRITE) - rw = WRITE; - else - rw = READ; - - ret = BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio, - failrec->last_mirror, - failrec->bio_flags, 0); - return ret; -} - -/* - * each time an IO finishes, we do a fast check in the IO failure tree - * to see if we need to process or clean up an io_failure_record - */ -static int btrfs_clean_io_failures(struct inode *inode, u64 start) -{ - u64 private; - u64 private_failure; - struct io_failure_record *failure; - int ret; - - private = 0; - if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private, - (u64)-1, 1, EXTENT_DIRTY, 0)) { - ret = get_state_private(&BTRFS_I(inode)->io_failure_tree, - start, &private_failure); - if (ret == 0) { - failure = (struct io_failure_record *)(unsigned long) - private_failure; - set_state_private(&BTRFS_I(inode)->io_failure_tree, - failure->start, 0); - clear_extent_bits(&BTRFS_I(inode)->io_failure_tree, - failure->start, - failure->start + failure->len - 1, - EXTENT_DIRTY | EXTENT_LOCKED, - GFP_NOFS); - kfree(failure); - } - } - return 0; -} - /* * when reads are done, we need to check csums to verify the data is correct - * if there's a match, we allow the bio to finish. If not, we go through - * the io_failure_record routines to find good copies + * if there's a match, we allow the bio to finish. If not, the code in + * extent_io.c will try to find good copies for us. */ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end, struct extent_state *state) @@ -2011,10 +1867,6 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end, kunmap_atomic(kaddr, KM_USER0); good: - /* if the io failure tree for this inode is non-empty, - * check to see if we've recovered from a failed IO - */ - btrfs_clean_io_failures(inode, start); return 0; zeroit: @@ -7420,7 +7272,6 @@ static struct extent_io_ops btrfs_extent_io_ops = { .readpage_end_io_hook = btrfs_readpage_end_io_hook, .writepage_end_io_hook = btrfs_writepage_end_io_hook, .writepage_start_hook = btrfs_writepage_start_hook, - .readpage_io_failed_hook = btrfs_io_failed_hook, .set_bit_hook = btrfs_set_bit_hook, .clear_bit_hook = btrfs_clear_bit_hook, .merge_extent_hook = btrfs_merge_extent_hook, From 5da6fcbc4eb50c0f55d520750332f5a6ab13508c Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 4 Aug 2011 18:11:04 +0200 Subject: [PATCH 0488/1596] btrfs: integrating raid-repair and scrub-fixup-nodatasum This ties nodatasum fixup in scrub together with raid repair patches. While both series are working fine alone, scrub will report uncorrectable errors if they occur in a nodatasum extent *and* the page is in the page cache. Previously, we would have triggered readpage to find good data and do the repair. However, readpage wouldn't read anything in the case where the page is up to date in the cache. So, we simply take that good data we have and call repair_io_failure directly (unless the page in the cache is dirty). Signed-off-by: Jan Schmidt --- fs/btrfs/scrub.c | 92 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 97142a218f0a..eba42e5fd5fd 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -24,6 +24,7 @@ #include "ordered-data.h" #include "transaction.h" #include "backref.h" +#include "extent_io.h" /* * This is only the first step towards a full-features scrub. It reads all @@ -360,13 +361,13 @@ static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio, static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx) { - struct page *page; + struct page *page = NULL; unsigned long index; struct scrub_fixup_nodatasum *fixup = ctx; int ret; - int corrected; + int corrected = 0; struct btrfs_key key; - struct inode *inode; + struct inode *inode = NULL; u64 end = offset + PAGE_SIZE - 1; struct btrfs_root *local_root; @@ -384,34 +385,75 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx) if (IS_ERR(inode)) return PTR_ERR(inode); - ret = set_extent_bit(&BTRFS_I(inode)->io_tree, offset, end, - EXTENT_DAMAGED, 0, NULL, NULL, GFP_NOFS); - - /* set_extent_bit should either succeed or give proper error */ - WARN_ON(ret > 0); - if (ret) - return ret < 0 ? ret : -EFAULT; - index = offset >> PAGE_CACHE_SHIFT; page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); - if (!page) - return -ENOMEM; + if (!page) { + ret = -ENOMEM; + goto out; + } + + if (PageUptodate(page)) { + struct btrfs_mapping_tree *map_tree; + if (PageDirty(page)) { + /* + * we need to write the data to the defect sector. the + * data that was in that sector is not in memory, + * because the page was modified. we must not write the + * modified page to that sector. + * + * TODO: what could be done here: wait for the delalloc + * runner to write out that page (might involve + * COW) and see whether the sector is still + * referenced afterwards. + * + * For the meantime, we'll treat this error + * incorrectable, although there is a chance that a + * later scrub will find the bad sector again and that + * there's no dirty page in memory, then. + */ + ret = -EIO; + goto out; + } + map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree; + ret = repair_io_failure(map_tree, offset, PAGE_SIZE, + fixup->logical, page, + fixup->mirror_num); + unlock_page(page); + corrected = !ret; + } else { + /* + * we need to get good data first. the general readpage path + * will call repair_io_failure for us, we just have to make + * sure we read the bad mirror. + */ + ret = set_extent_bits(&BTRFS_I(inode)->io_tree, offset, end, + EXTENT_DAMAGED, GFP_NOFS); + if (ret) { + /* set_extent_bits should give proper error */ + WARN_ON(ret > 0); + if (ret > 0) + ret = -EFAULT; + goto out; + } - ret = extent_read_full_page(&BTRFS_I(inode)->io_tree, page, - btrfs_get_extent, fixup->mirror_num); - wait_on_page_locked(page); - corrected = !test_range_bit(&BTRFS_I(inode)->io_tree, offset, end, - EXTENT_DAMAGED, 0, NULL); + ret = extent_read_full_page(&BTRFS_I(inode)->io_tree, page, + btrfs_get_extent, + fixup->mirror_num); + wait_on_page_locked(page); - if (corrected) - WARN_ON(!PageUptodate(page)); - else - clear_extent_bit(&BTRFS_I(inode)->io_tree, offset, end, - EXTENT_DAMAGED, 0, 0, NULL, GFP_NOFS); + corrected = !test_range_bit(&BTRFS_I(inode)->io_tree, offset, + end, EXTENT_DAMAGED, 0, NULL); + if (!corrected) + clear_extent_bits(&BTRFS_I(inode)->io_tree, offset, end, + EXTENT_DAMAGED, GFP_NOFS); + } - put_page(page); - iput(inode); +out: + if (page) + put_page(page); + if (inode) + iput(inode); if (ret < 0) return ret; From 4dcaebbf6586d299be8513512a1253f177b803d7 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 29 Sep 2011 16:53:29 +0100 Subject: [PATCH 0489/1596] xen: use generic functions instead of xen_{alloc, free}_vm_area() Replace calls to the Xen-specific xen_alloc_vm_area() and xen_free_vm_area() functions with the generic equivalent (alloc_vm_area() and free_vm_area()). On x86, these were identical already. Signed-off-by: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk --- arch/ia64/include/asm/xen/grant_table.h | 29 ------------ arch/ia64/xen/grant-table.c | 62 ------------------------- arch/x86/include/asm/xen/grant_table.h | 7 --- arch/x86/xen/grant-table.c | 2 +- drivers/xen/xenbus/xenbus_client.c | 6 +-- include/xen/grant_table.h | 1 - 6 files changed, 4 insertions(+), 103 deletions(-) delete mode 100644 arch/ia64/include/asm/xen/grant_table.h delete mode 100644 arch/x86/include/asm/xen/grant_table.h diff --git a/arch/ia64/include/asm/xen/grant_table.h b/arch/ia64/include/asm/xen/grant_table.h deleted file mode 100644 index 2b1fae0e2d11..000000000000 --- a/arch/ia64/include/asm/xen/grant_table.h +++ /dev/null @@ -1,29 +0,0 @@ -/****************************************************************************** - * arch/ia64/include/asm/xen/grant_table.h - * - * Copyright (c) 2008 Isaku Yamahata - * VA Linux Systems Japan K.K. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef _ASM_IA64_XEN_GRANT_TABLE_H -#define _ASM_IA64_XEN_GRANT_TABLE_H - -struct vm_struct *xen_alloc_vm_area(unsigned long size); -void xen_free_vm_area(struct vm_struct *area); - -#endif /* _ASM_IA64_XEN_GRANT_TABLE_H */ diff --git a/arch/ia64/xen/grant-table.c b/arch/ia64/xen/grant-table.c index 48cca37625eb..c18281332f84 100644 --- a/arch/ia64/xen/grant-table.c +++ b/arch/ia64/xen/grant-table.c @@ -31,68 +31,6 @@ #include -struct vm_struct *xen_alloc_vm_area(unsigned long size) -{ - int order; - unsigned long virt; - unsigned long nr_pages; - struct vm_struct *area; - - order = get_order(size); - virt = __get_free_pages(GFP_KERNEL, order); - if (virt == 0) - goto err0; - nr_pages = 1 << order; - scrub_pages(virt, nr_pages); - - area = kmalloc(sizeof(*area), GFP_KERNEL); - if (area == NULL) - goto err1; - - area->flags = VM_IOREMAP; - area->addr = (void *)virt; - area->size = size; - area->pages = NULL; - area->nr_pages = nr_pages; - area->phys_addr = 0; /* xenbus_map_ring_valloc uses this field! */ - - return area; - -err1: - free_pages(virt, order); -err0: - return NULL; -} -EXPORT_SYMBOL_GPL(xen_alloc_vm_area); - -void xen_free_vm_area(struct vm_struct *area) -{ - unsigned int order = get_order(area->size); - unsigned long i; - unsigned long phys_addr = __pa(area->addr); - - /* This area is used for foreign page mappping. - * So underlying machine page may not be assigned. */ - for (i = 0; i < (1 << order); i++) { - unsigned long ret; - unsigned long gpfn = (phys_addr >> PAGE_SHIFT) + i; - struct xen_memory_reservation reservation = { - .nr_extents = 1, - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF - }; - set_xen_guest_handle(reservation.extent_start, &gpfn); - ret = HYPERVISOR_memory_op(XENMEM_populate_physmap, - &reservation); - BUG_ON(ret != 1); - } - free_pages((unsigned long)area->addr, order); - kfree(area); -} -EXPORT_SYMBOL_GPL(xen_free_vm_area); - - /**************************************************************************** * grant table hack * cmd: GNTTABOP_xxx diff --git a/arch/x86/include/asm/xen/grant_table.h b/arch/x86/include/asm/xen/grant_table.h deleted file mode 100644 index fdbbb45767a6..000000000000 --- a/arch/x86/include/asm/xen/grant_table.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _ASM_X86_XEN_GRANT_TABLE_H -#define _ASM_X86_XEN_GRANT_TABLE_H - -#define xen_alloc_vm_area(size) alloc_vm_area(size) -#define xen_free_vm_area(area) free_vm_area(area) - -#endif /* _ASM_X86_XEN_GRANT_TABLE_H */ diff --git a/arch/x86/xen/grant-table.c b/arch/x86/xen/grant-table.c index 49ba9b5224d1..6bbfd7ac5e81 100644 --- a/arch/x86/xen/grant-table.c +++ b/arch/x86/xen/grant-table.c @@ -71,7 +71,7 @@ int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, if (shared == NULL) { struct vm_struct *area = - xen_alloc_vm_area(PAGE_SIZE * max_nr_gframes); + alloc_vm_area(PAGE_SIZE * max_nr_gframes); BUG_ON(area == NULL); shared = area->addr; *__shared = shared; diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index cdacf923e073..229d3adce85d 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -443,7 +443,7 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) *vaddr = NULL; - area = xen_alloc_vm_area(PAGE_SIZE); + area = alloc_vm_area(PAGE_SIZE); if (!area) return -ENOMEM; @@ -453,7 +453,7 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) BUG(); if (op.status != GNTST_okay) { - xen_free_vm_area(area); + free_vm_area(area); xenbus_dev_fatal(dev, op.status, "mapping in shared page %d from domain %d", gnt_ref, dev->otherend_id); @@ -552,7 +552,7 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) BUG(); if (op.status == GNTST_okay) - xen_free_vm_area(area); + free_vm_area(area); else xenbus_dev_error(dev, op.status, "unmapping page at handle %d error %d", diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index b1fab6b5b3ef..8a8bb7626f7c 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h @@ -43,7 +43,6 @@ #include #include -#include #include From 1bba688b5a32079db616f281c13f00944d74020b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 26 Sep 2011 10:13:03 +0800 Subject: [PATCH 0490/1596] mtd: r852: make r852_pm_ops static It is not used outside this driver so no need to make the symbol global. Also make r852_suspend and r852_resume static. Signed-off-by: Axel Lin Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/r852.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index cae2e013c986..f20f393bfda6 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -1027,7 +1027,7 @@ void r852_shutdown(struct pci_dev *pci_dev) } #ifdef CONFIG_PM -int r852_suspend(struct device *device) +static int r852_suspend(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1048,7 +1048,7 @@ int r852_suspend(struct device *device) return 0; } -int r852_resume(struct device *device) +static int r852_resume(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1092,7 +1092,7 @@ static const struct pci_device_id r852_pci_id_tbl[] = { MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl); -SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); +static SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); static struct pci_driver r852_pci_driver = { .name = DRV_NAME, From bb82ab88dfdb12948af58989c75bfe904bc1b09d Mon Sep 17 00:00:00 2001 From: Arne Jansen Date: Fri, 10 Jun 2011 14:06:53 +0200 Subject: [PATCH 0491/1596] btrfs: add an extra wait mode to read_extent_buffer_pages read_extent_buffer_pages currently has two modes, either trigger a read without waiting for anything, or wait for the I/O to finish. The former also bails when it's unable to lock the page. This patch now adds an additional parameter to allow it to block on page lock, but don't wait for completion. Changes v5: - merge the 2 wait parameters into one and define WAIT_NONE, WAIT_COMPLETE and WAIT_PAGE_LOCK Change v6: - fix bug introduced in v5 Signed-off-by: Arne Jansen --- fs/btrfs/disk-io.c | 5 +++-- fs/btrfs/extent_io.c | 7 +++---- fs/btrfs/extent_io.h | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 07b3ac662e19..e6170e142cad 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -367,7 +367,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; while (1) { - ret = read_extent_buffer_pages(io_tree, eb, start, 1, + ret = read_extent_buffer_pages(io_tree, eb, start, + WAIT_COMPLETE, btree_get_extent, mirror_num); if (!ret && !verify_parent_transid(io_tree, eb, parent_transid)) @@ -974,7 +975,7 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, if (!buf) return 0; read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, - buf, 0, 0, btree_get_extent, 0); + buf, 0, WAIT_NONE, btree_get_extent, 0); free_extent_buffer(buf); return ret; } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index d418164a35f1..823028e73cf8 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -3349,8 +3349,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree, } int read_extent_buffer_pages(struct extent_io_tree *tree, - struct extent_buffer *eb, - u64 start, int wait, + struct extent_buffer *eb, u64 start, int wait, get_extent_t *get_extent, int mirror_num) { unsigned long i; @@ -3386,7 +3385,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, num_pages = num_extent_pages(eb->start, eb->len); for (i = start_i; i < num_pages; i++) { page = extent_buffer_page(eb, i); - if (!wait) { + if (wait == WAIT_NONE) { if (!trylock_page(page)) goto unlock_exit; } else { @@ -3430,7 +3429,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, if (bio) submit_one_bio(READ, bio, mirror_num, bio_flags); - if (ret || !wait) + if (ret || wait != WAIT_COMPLETE) return ret; for (i = start_i; i < num_pages; i++) { diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 7b2f0c3e7929..6d74c6b34691 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -248,6 +248,9 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, u64 start, unsigned long len); void free_extent_buffer(struct extent_buffer *eb); +#define WAIT_NONE 0 +#define WAIT_COMPLETE 1 +#define WAIT_PAGE_LOCK 2 int read_extent_buffer_pages(struct extent_io_tree *tree, struct extent_buffer *eb, u64 start, int wait, get_extent_t *get_extent, int mirror_num); From ab0fff03055d2d1b01a7581badeba18db9c4f55c Mon Sep 17 00:00:00 2001 From: Arne Jansen Date: Mon, 23 May 2011 14:25:41 +0200 Subject: [PATCH 0492/1596] btrfs: add READAHEAD extent buffer flag Add a READAHEAD extent buffer flag. Add a function to trigger a read with this flag set. Changes v2: - use extent buffer flags instead of extent state flags Changes v5: - adapt to changed read_extent_buffer_pages interface - don't return eb from reada_tree_block_flagged if it has CORRUPT flag set Signed-off-by: Arne Jansen --- fs/btrfs/disk-io.c | 32 ++++++++++++++++++++++++++++++++ fs/btrfs/disk-io.h | 2 ++ fs/btrfs/extent_io.h | 1 + 3 files changed, 35 insertions(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e6170e142cad..1220d04072c8 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -980,6 +980,38 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, return ret; } +int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, u32 blocksize, + int mirror_num, struct extent_buffer **eb) +{ + struct extent_buffer *buf = NULL; + struct inode *btree_inode = root->fs_info->btree_inode; + struct extent_io_tree *io_tree = &BTRFS_I(btree_inode)->io_tree; + int ret; + + buf = btrfs_find_create_tree_block(root, bytenr, blocksize); + if (!buf) + return 0; + + set_bit(EXTENT_BUFFER_READAHEAD, &buf->bflags); + + ret = read_extent_buffer_pages(io_tree, buf, 0, WAIT_PAGE_LOCK, + btree_get_extent, mirror_num); + if (ret) { + free_extent_buffer(buf); + return ret; + } + + if (test_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags)) { + free_extent_buffer(buf); + return -EIO; + } else if (extent_buffer_uptodate(io_tree, buf, NULL)) { + *eb = buf; + } else { + free_extent_buffer(buf); + } + return 0; +} + struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) { diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index bec3ea4bd67f..b3bdb5c1390f 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -40,6 +40,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid); int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid); +int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, u32 blocksize, + int mirror_num, struct extent_buffer **eb); struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize); int clean_tree_block(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 6d74c6b34691..fcaf49bcb880 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -32,6 +32,7 @@ #define EXTENT_BUFFER_BLOCKING 1 #define EXTENT_BUFFER_DIRTY 2 #define EXTENT_BUFFER_CORRUPT 3 +#define EXTENT_BUFFER_READAHEAD 4 /* this got triggered by readahead */ /* these are flags for extent_clear_unlock_delalloc */ #define EXTENT_CLEAR_UNLOCK_PAGE 0x1 From 90519d66abbccc251d14719ac76f191f70826e40 Mon Sep 17 00:00:00 2001 From: Arne Jansen Date: Mon, 23 May 2011 14:30:00 +0200 Subject: [PATCH 0493/1596] btrfs: state information for readahead Add state information for readahead to btrfs_fs_info and btrfs_device Changes v2: - don't wait in radix_trees - add own set of workers for readahead Reviewed-by: Josef Bacik Signed-off-by: Arne Jansen --- fs/btrfs/ctree.h | 5 +++++ fs/btrfs/disk-io.c | 10 ++++++++++ fs/btrfs/volumes.c | 8 ++++++++ fs/btrfs/volumes.h | 8 ++++++++ 4 files changed, 31 insertions(+) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 03912c5c6f49..f71fd24cc152 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1036,6 +1036,7 @@ struct btrfs_fs_info { struct btrfs_workers endio_freespace_worker; struct btrfs_workers submit_workers; struct btrfs_workers caching_workers; + struct btrfs_workers readahead_workers; /* * fixup workers take dirty pages that didn't properly go through @@ -1119,6 +1120,10 @@ struct btrfs_fs_info { u64 fs_state; struct btrfs_delayed_root *delayed_root; + + /* readahead tree */ + spinlock_t reada_lock; + struct radix_tree_root reada_tree; }; /* diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 1220d04072c8..fd28c40e9ec3 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1711,6 +1711,10 @@ struct btrfs_root *open_ctree(struct super_block *sb, fs_info->defrag_inodes = RB_ROOT; fs_info->trans_no_join = 0; + /* readahead state */ + INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT); + spin_lock_init(&fs_info->reada_lock); + fs_info->thread_pool_size = min_t(unsigned long, num_online_cpus() + 2, 8); @@ -1903,6 +1907,9 @@ struct btrfs_root *open_ctree(struct super_block *sb, btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta", fs_info->thread_pool_size, &fs_info->generic_worker); + btrfs_init_workers(&fs_info->readahead_workers, "readahead", + fs_info->thread_pool_size, + &fs_info->generic_worker); /* * endios are largely parallel and should have a very @@ -1913,6 +1920,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, fs_info->endio_write_workers.idle_thresh = 2; fs_info->endio_meta_write_workers.idle_thresh = 2; + fs_info->readahead_workers.idle_thresh = 2; btrfs_start_workers(&fs_info->workers, 1); btrfs_start_workers(&fs_info->generic_worker, 1); @@ -1926,6 +1934,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, btrfs_start_workers(&fs_info->endio_freespace_worker, 1); btrfs_start_workers(&fs_info->delayed_workers, 1); btrfs_start_workers(&fs_info->caching_workers, 1); + btrfs_start_workers(&fs_info->readahead_workers, 1); fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, @@ -2650,6 +2659,7 @@ int close_ctree(struct btrfs_root *root) btrfs_stop_workers(&fs_info->submit_workers); btrfs_stop_workers(&fs_info->delayed_workers); btrfs_stop_workers(&fs_info->caching_workers); + btrfs_stop_workers(&fs_info->readahead_workers); btrfs_close_devices(fs_info->fs_devices); btrfs_mapping_tree_free(&fs_info->mapping_tree); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f2a4cc79da61..1dccce5bc93d 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -366,6 +366,14 @@ static noinline int device_list_add(const char *path, } INIT_LIST_HEAD(&device->dev_alloc_list); + /* init readahead state */ + spin_lock_init(&device->reada_lock); + device->reada_curr_zone = NULL; + atomic_set(&device->reada_in_flight, 0); + device->reada_next = 0; + INIT_RADIX_TREE(&device->reada_zones, GFP_NOFS & ~__GFP_WAIT); + INIT_RADIX_TREE(&device->reada_extents, GFP_NOFS & ~__GFP_WAIT); + mutex_lock(&fs_devices->device_list_mutex); list_add_rcu(&device->dev_list, &fs_devices->devices); mutex_unlock(&fs_devices->device_list_mutex); diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 6d866db4e177..2a751246188a 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -92,6 +92,14 @@ struct btrfs_device { struct btrfs_work work; struct rcu_head rcu; struct work_struct rcu_work; + + /* readahead state */ + spinlock_t reada_lock; + atomic_t reada_in_flight; + u64 reada_next; + struct reada_zone *reada_curr_zone; + struct radix_tree_root reada_zones; + struct radix_tree_root reada_extents; }; struct btrfs_fs_devices { From 7414a03fbf9e75fbbf2a3c16828cd862e572aa44 Mon Sep 17 00:00:00 2001 From: Arne Jansen Date: Mon, 23 May 2011 14:33:49 +0200 Subject: [PATCH 0494/1596] btrfs: initial readahead code and prototypes This is the implementation for the generic read ahead framework. To trigger a readahead, btrfs_reada_add must be called. It will start a read ahead for the given range [start, end) on tree root. The returned handle can either be used to wait on the readahead to finish (btrfs_reada_wait), or to send it to the background (btrfs_reada_detach). The read ahead works as follows: On btrfs_reada_add, the root of the tree is inserted into a radix_tree. reada_start_machine will then search for extents to prefetch and trigger some reads. When a read finishes for a node, all contained node/leaf pointers that lie in the given range will also be enqueued. The reads will be triggered in sequential order, thus giving a big win over a naive enumeration. It will also make use of multi-device layouts. Each disk will have its on read pointer and all disks will by utilized in parallel. Also will no two disks read both sides of a mirror simultaneously, as this would waste seeking capacity. Instead both disks will read different parts of the filesystem. Any number of readaheads can be started in parallel. The read order will be determined globally, i.e. 2 parallel readaheads will normally finish faster than the 2 started one after another. Changes v2: - protect root->node by transaction instead of node_lock - fix missed branches: The readahead had a too simple check to determine if a branch from a node should be checked or not. It now also records the upper bound of each node to see if the requested RA range lies within. - use KERN_CONT to debug output, to avoid line breaks - defer reada_start_machine to worker to avoid deadlock Changes v3: - protect root->node by rcu Changes v5: - changed EIO-semantics of reada_tree_block_flagged - remove spin_lock from reada_control and make elems an atomic_t - remove unused read_total from reada_control - kill reada_key_cmp, use btrfs_comp_cpu_keys instead - use kref-style release functions where possible - return struct reada_control * instead of void * from btrfs_reada_add Signed-off-by: Arne Jansen --- fs/btrfs/Makefile | 3 +- fs/btrfs/ctree.h | 16 + fs/btrfs/reada.c | 949 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 967 insertions(+), 1 deletion(-) create mode 100644 fs/btrfs/reada.c diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index 40e6ac08c21f..bdd6fb238ce1 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -7,6 +7,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o \ - compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o + compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ + reada.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f71fd24cc152..370af767440d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2702,4 +2702,20 @@ int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid); int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, struct btrfs_scrub_progress *progress); +/* reada.c */ +struct reada_control { + struct btrfs_root *root; /* tree to prefetch */ + struct btrfs_key key_start; + struct btrfs_key key_end; /* exclusive */ + atomic_t elems; + struct kref refcnt; + wait_queue_head_t wait; +}; +struct reada_control *btrfs_reada_add(struct btrfs_root *root, + struct btrfs_key *start, struct btrfs_key *end); +int btrfs_reada_wait(void *handle); +void btrfs_reada_detach(void *handle); +int btree_readahead_hook(struct btrfs_root *root, struct extent_buffer *eb, + u64 start, int err); + #endif diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c new file mode 100644 index 000000000000..2b701d082227 --- /dev/null +++ b/fs/btrfs/reada.c @@ -0,0 +1,949 @@ +/* + * Copyright (C) 2011 STRATO. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ctree.h" +#include "volumes.h" +#include "disk-io.h" +#include "transaction.h" + +#undef DEBUG + +/* + * This is the implementation for the generic read ahead framework. + * + * To trigger a readahead, btrfs_reada_add must be called. It will start + * a read ahead for the given range [start, end) on tree root. The returned + * handle can either be used to wait on the readahead to finish + * (btrfs_reada_wait), or to send it to the background (btrfs_reada_detach). + * + * The read ahead works as follows: + * On btrfs_reada_add, the root of the tree is inserted into a radix_tree. + * reada_start_machine will then search for extents to prefetch and trigger + * some reads. When a read finishes for a node, all contained node/leaf + * pointers that lie in the given range will also be enqueued. The reads will + * be triggered in sequential order, thus giving a big win over a naive + * enumeration. It will also make use of multi-device layouts. Each disk + * will have its on read pointer and all disks will by utilized in parallel. + * Also will no two disks read both sides of a mirror simultaneously, as this + * would waste seeking capacity. Instead both disks will read different parts + * of the filesystem. + * Any number of readaheads can be started in parallel. The read order will be + * determined globally, i.e. 2 parallel readaheads will normally finish faster + * than the 2 started one after another. + */ + +#define MAX_MIRRORS 2 +#define MAX_IN_FLIGHT 6 + +struct reada_extctl { + struct list_head list; + struct reada_control *rc; + u64 generation; +}; + +struct reada_extent { + u64 logical; + struct btrfs_key top; + u32 blocksize; + int err; + struct list_head extctl; + struct kref refcnt; + spinlock_t lock; + struct reada_zone *zones[MAX_MIRRORS]; + int nzones; + struct btrfs_device *scheduled_for; +}; + +struct reada_zone { + u64 start; + u64 end; + u64 elems; + struct list_head list; + spinlock_t lock; + int locked; + struct btrfs_device *device; + struct btrfs_device *devs[MAX_MIRRORS]; /* full list, incl self */ + int ndevs; + struct kref refcnt; +}; + +struct reada_machine_work { + struct btrfs_work work; + struct btrfs_fs_info *fs_info; +}; + +static void reada_extent_put(struct btrfs_fs_info *, struct reada_extent *); +static void reada_control_release(struct kref *kref); +static void reada_zone_release(struct kref *kref); +static void reada_start_machine(struct btrfs_fs_info *fs_info); +static void __reada_start_machine(struct btrfs_fs_info *fs_info); + +static int reada_add_block(struct reada_control *rc, u64 logical, + struct btrfs_key *top, int level, u64 generation); + +/* recurses */ +/* in case of err, eb might be NULL */ +static int __readahead_hook(struct btrfs_root *root, struct extent_buffer *eb, + u64 start, int err) +{ + int level = 0; + int nritems; + int i; + u64 bytenr; + u64 generation; + struct reada_extent *re; + struct btrfs_fs_info *fs_info = root->fs_info; + struct list_head list; + unsigned long index = start >> PAGE_CACHE_SHIFT; + struct btrfs_device *for_dev; + + if (eb) + level = btrfs_header_level(eb); + + /* find extent */ + spin_lock(&fs_info->reada_lock); + re = radix_tree_lookup(&fs_info->reada_tree, index); + if (re) + kref_get(&re->refcnt); + spin_unlock(&fs_info->reada_lock); + + if (!re) + return -1; + + spin_lock(&re->lock); + /* + * just take the full list from the extent. afterwards we + * don't need the lock anymore + */ + list_replace_init(&re->extctl, &list); + for_dev = re->scheduled_for; + re->scheduled_for = NULL; + spin_unlock(&re->lock); + + if (err == 0) { + nritems = level ? btrfs_header_nritems(eb) : 0; + generation = btrfs_header_generation(eb); + /* + * FIXME: currently we just set nritems to 0 if this is a leaf, + * effectively ignoring the content. In a next step we could + * trigger more readahead depending from the content, e.g. + * fetch the checksums for the extents in the leaf. + */ + } else { + /* + * this is the error case, the extent buffer has not been + * read correctly. We won't access anything from it and + * just cleanup our data structures. Effectively this will + * cut the branch below this node from read ahead. + */ + nritems = 0; + generation = 0; + } + + for (i = 0; i < nritems; i++) { + struct reada_extctl *rec; + u64 n_gen; + struct btrfs_key key; + struct btrfs_key next_key; + + btrfs_node_key_to_cpu(eb, &key, i); + if (i + 1 < nritems) + btrfs_node_key_to_cpu(eb, &next_key, i + 1); + else + next_key = re->top; + bytenr = btrfs_node_blockptr(eb, i); + n_gen = btrfs_node_ptr_generation(eb, i); + + list_for_each_entry(rec, &list, list) { + struct reada_control *rc = rec->rc; + + /* + * if the generation doesn't match, just ignore this + * extctl. This will probably cut off a branch from + * prefetch. Alternatively one could start a new (sub-) + * prefetch for this branch, starting again from root. + * FIXME: move the generation check out of this loop + */ +#ifdef DEBUG + if (rec->generation != generation) { + printk(KERN_DEBUG "generation mismatch for " + "(%llu,%d,%llu) %llu != %llu\n", + key.objectid, key.type, key.offset, + rec->generation, generation); + } +#endif + if (rec->generation == generation && + btrfs_comp_cpu_keys(&key, &rc->key_end) < 0 && + btrfs_comp_cpu_keys(&next_key, &rc->key_start) > 0) + reada_add_block(rc, bytenr, &next_key, + level - 1, n_gen); + } + } + /* + * free extctl records + */ + while (!list_empty(&list)) { + struct reada_control *rc; + struct reada_extctl *rec; + + rec = list_first_entry(&list, struct reada_extctl, list); + list_del(&rec->list); + rc = rec->rc; + kfree(rec); + + kref_get(&rc->refcnt); + if (atomic_dec_and_test(&rc->elems)) { + kref_put(&rc->refcnt, reada_control_release); + wake_up(&rc->wait); + } + kref_put(&rc->refcnt, reada_control_release); + + reada_extent_put(fs_info, re); /* one ref for each entry */ + } + reada_extent_put(fs_info, re); /* our ref */ + if (for_dev) + atomic_dec(&for_dev->reada_in_flight); + + return 0; +} + +/* + * start is passed separately in case eb in NULL, which may be the case with + * failed I/O + */ +int btree_readahead_hook(struct btrfs_root *root, struct extent_buffer *eb, + u64 start, int err) +{ + int ret; + + ret = __readahead_hook(root, eb, start, err); + + reada_start_machine(root->fs_info); + + return ret; +} + +static struct reada_zone *reada_find_zone(struct btrfs_fs_info *fs_info, + struct btrfs_device *dev, u64 logical, + struct btrfs_multi_bio *multi) +{ + int ret; + int looped = 0; + struct reada_zone *zone; + struct btrfs_block_group_cache *cache = NULL; + u64 start; + u64 end; + int i; + +again: + zone = NULL; + spin_lock(&fs_info->reada_lock); + ret = radix_tree_gang_lookup(&dev->reada_zones, (void **)&zone, + logical >> PAGE_CACHE_SHIFT, 1); + if (ret == 1) + kref_get(&zone->refcnt); + spin_unlock(&fs_info->reada_lock); + + if (ret == 1) { + if (logical >= zone->start && logical < zone->end) + return zone; + spin_lock(&fs_info->reada_lock); + kref_put(&zone->refcnt, reada_zone_release); + spin_unlock(&fs_info->reada_lock); + } + + if (looped) + return NULL; + + cache = btrfs_lookup_block_group(fs_info, logical); + if (!cache) + return NULL; + + start = cache->key.objectid; + end = start + cache->key.offset - 1; + btrfs_put_block_group(cache); + + zone = kzalloc(sizeof(*zone), GFP_NOFS); + if (!zone) + return NULL; + + zone->start = start; + zone->end = end; + INIT_LIST_HEAD(&zone->list); + spin_lock_init(&zone->lock); + zone->locked = 0; + kref_init(&zone->refcnt); + zone->elems = 0; + zone->device = dev; /* our device always sits at index 0 */ + for (i = 0; i < multi->num_stripes; ++i) { + /* bounds have already been checked */ + zone->devs[i] = multi->stripes[i].dev; + } + zone->ndevs = multi->num_stripes; + + spin_lock(&fs_info->reada_lock); + ret = radix_tree_insert(&dev->reada_zones, + (unsigned long)zone->end >> PAGE_CACHE_SHIFT, + zone); + spin_unlock(&fs_info->reada_lock); + + if (ret) { + kfree(zone); + looped = 1; + goto again; + } + + return zone; +} + +static struct reada_extent *reada_find_extent(struct btrfs_root *root, + u64 logical, + struct btrfs_key *top, int level) +{ + int ret; + int looped = 0; + struct reada_extent *re = NULL; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; + struct btrfs_multi_bio *multi = NULL; + struct btrfs_device *dev; + u32 blocksize; + u64 length; + int nzones = 0; + int i; + unsigned long index = logical >> PAGE_CACHE_SHIFT; + +again: + spin_lock(&fs_info->reada_lock); + re = radix_tree_lookup(&fs_info->reada_tree, index); + if (re) + kref_get(&re->refcnt); + spin_unlock(&fs_info->reada_lock); + + if (re || looped) + return re; + + re = kzalloc(sizeof(*re), GFP_NOFS); + if (!re) + return NULL; + + blocksize = btrfs_level_size(root, level); + re->logical = logical; + re->blocksize = blocksize; + re->top = *top; + INIT_LIST_HEAD(&re->extctl); + spin_lock_init(&re->lock); + kref_init(&re->refcnt); + + /* + * map block + */ + length = blocksize; + ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length, &multi, 0); + if (ret || !multi || length < blocksize) + goto error; + + if (multi->num_stripes > MAX_MIRRORS) { + printk(KERN_ERR "btrfs readahead: more than %d copies not " + "supported", MAX_MIRRORS); + goto error; + } + + for (nzones = 0; nzones < multi->num_stripes; ++nzones) { + struct reada_zone *zone; + + dev = multi->stripes[nzones].dev; + zone = reada_find_zone(fs_info, dev, logical, multi); + if (!zone) + break; + + re->zones[nzones] = zone; + spin_lock(&zone->lock); + if (!zone->elems) + kref_get(&zone->refcnt); + ++zone->elems; + spin_unlock(&zone->lock); + spin_lock(&fs_info->reada_lock); + kref_put(&zone->refcnt, reada_zone_release); + spin_unlock(&fs_info->reada_lock); + } + re->nzones = nzones; + if (nzones == 0) { + /* not a single zone found, error and out */ + goto error; + } + + /* insert extent in reada_tree + all per-device trees, all or nothing */ + spin_lock(&fs_info->reada_lock); + ret = radix_tree_insert(&fs_info->reada_tree, index, re); + if (ret) { + spin_unlock(&fs_info->reada_lock); + if (ret != -ENOMEM) { + /* someone inserted the extent in the meantime */ + looped = 1; + } + goto error; + } + for (i = 0; i < nzones; ++i) { + dev = multi->stripes[i].dev; + ret = radix_tree_insert(&dev->reada_extents, index, re); + if (ret) { + while (--i >= 0) { + dev = multi->stripes[i].dev; + BUG_ON(dev == NULL); + radix_tree_delete(&dev->reada_extents, index); + } + BUG_ON(fs_info == NULL); + radix_tree_delete(&fs_info->reada_tree, index); + spin_unlock(&fs_info->reada_lock); + goto error; + } + } + spin_unlock(&fs_info->reada_lock); + + return re; + +error: + while (nzones) { + struct reada_zone *zone; + + --nzones; + zone = re->zones[nzones]; + kref_get(&zone->refcnt); + spin_lock(&zone->lock); + --zone->elems; + if (zone->elems == 0) { + /* + * no fs_info->reada_lock needed, as this can't be + * the last ref + */ + kref_put(&zone->refcnt, reada_zone_release); + } + spin_unlock(&zone->lock); + + spin_lock(&fs_info->reada_lock); + kref_put(&zone->refcnt, reada_zone_release); + spin_unlock(&fs_info->reada_lock); + } + kfree(re); + if (looped) + goto again; + return NULL; +} + +static void reada_kref_dummy(struct kref *kr) +{ +} + +static void reada_extent_put(struct btrfs_fs_info *fs_info, + struct reada_extent *re) +{ + int i; + unsigned long index = re->logical >> PAGE_CACHE_SHIFT; + + spin_lock(&fs_info->reada_lock); + if (!kref_put(&re->refcnt, reada_kref_dummy)) { + spin_unlock(&fs_info->reada_lock); + return; + } + + radix_tree_delete(&fs_info->reada_tree, index); + for (i = 0; i < re->nzones; ++i) { + struct reada_zone *zone = re->zones[i]; + + radix_tree_delete(&zone->device->reada_extents, index); + } + + spin_unlock(&fs_info->reada_lock); + + for (i = 0; i < re->nzones; ++i) { + struct reada_zone *zone = re->zones[i]; + + kref_get(&zone->refcnt); + spin_lock(&zone->lock); + --zone->elems; + if (zone->elems == 0) { + /* no fs_info->reada_lock needed, as this can't be + * the last ref */ + kref_put(&zone->refcnt, reada_zone_release); + } + spin_unlock(&zone->lock); + + spin_lock(&fs_info->reada_lock); + kref_put(&zone->refcnt, reada_zone_release); + spin_unlock(&fs_info->reada_lock); + } + if (re->scheduled_for) + atomic_dec(&re->scheduled_for->reada_in_flight); + + kfree(re); +} + +static void reada_zone_release(struct kref *kref) +{ + struct reada_zone *zone = container_of(kref, struct reada_zone, refcnt); + + radix_tree_delete(&zone->device->reada_zones, + zone->end >> PAGE_CACHE_SHIFT); + + kfree(zone); +} + +static void reada_control_release(struct kref *kref) +{ + struct reada_control *rc = container_of(kref, struct reada_control, + refcnt); + + kfree(rc); +} + +static int reada_add_block(struct reada_control *rc, u64 logical, + struct btrfs_key *top, int level, u64 generation) +{ + struct btrfs_root *root = rc->root; + struct reada_extent *re; + struct reada_extctl *rec; + + re = reada_find_extent(root, logical, top, level); /* takes one ref */ + if (!re) + return -1; + + rec = kzalloc(sizeof(*rec), GFP_NOFS); + if (!rec) { + reada_extent_put(root->fs_info, re); + return -1; + } + + rec->rc = rc; + rec->generation = generation; + atomic_inc(&rc->elems); + + spin_lock(&re->lock); + list_add_tail(&rec->list, &re->extctl); + spin_unlock(&re->lock); + + /* leave the ref on the extent */ + + return 0; +} + +/* + * called with fs_info->reada_lock held + */ +static void reada_peer_zones_set_lock(struct reada_zone *zone, int lock) +{ + int i; + unsigned long index = zone->end >> PAGE_CACHE_SHIFT; + + for (i = 0; i < zone->ndevs; ++i) { + struct reada_zone *peer; + peer = radix_tree_lookup(&zone->devs[i]->reada_zones, index); + if (peer && peer->device != zone->device) + peer->locked = lock; + } +} + +/* + * called with fs_info->reada_lock held + */ +static int reada_pick_zone(struct btrfs_device *dev) +{ + struct reada_zone *top_zone = NULL; + struct reada_zone *top_locked_zone = NULL; + u64 top_elems = 0; + u64 top_locked_elems = 0; + unsigned long index = 0; + int ret; + + if (dev->reada_curr_zone) { + reada_peer_zones_set_lock(dev->reada_curr_zone, 0); + kref_put(&dev->reada_curr_zone->refcnt, reada_zone_release); + dev->reada_curr_zone = NULL; + } + /* pick the zone with the most elements */ + while (1) { + struct reada_zone *zone; + + ret = radix_tree_gang_lookup(&dev->reada_zones, + (void **)&zone, index, 1); + if (ret == 0) + break; + index = (zone->end >> PAGE_CACHE_SHIFT) + 1; + if (zone->locked) { + if (zone->elems > top_locked_elems) { + top_locked_elems = zone->elems; + top_locked_zone = zone; + } + } else { + if (zone->elems > top_elems) { + top_elems = zone->elems; + top_zone = zone; + } + } + } + if (top_zone) + dev->reada_curr_zone = top_zone; + else if (top_locked_zone) + dev->reada_curr_zone = top_locked_zone; + else + return 0; + + dev->reada_next = dev->reada_curr_zone->start; + kref_get(&dev->reada_curr_zone->refcnt); + reada_peer_zones_set_lock(dev->reada_curr_zone, 1); + + return 1; +} + +static int reada_start_machine_dev(struct btrfs_fs_info *fs_info, + struct btrfs_device *dev) +{ + struct reada_extent *re = NULL; + int mirror_num = 0; + struct extent_buffer *eb = NULL; + u64 logical; + u32 blocksize; + int ret; + int i; + int need_kick = 0; + + spin_lock(&fs_info->reada_lock); + if (dev->reada_curr_zone == NULL) { + ret = reada_pick_zone(dev); + if (!ret) { + spin_unlock(&fs_info->reada_lock); + return 0; + } + } + /* + * FIXME currently we issue the reads one extent at a time. If we have + * a contiguous block of extents, we could also coagulate them or use + * plugging to speed things up + */ + ret = radix_tree_gang_lookup(&dev->reada_extents, (void **)&re, + dev->reada_next >> PAGE_CACHE_SHIFT, 1); + if (ret == 0 || re->logical >= dev->reada_curr_zone->end) { + ret = reada_pick_zone(dev); + if (!ret) { + spin_unlock(&fs_info->reada_lock); + return 0; + } + re = NULL; + ret = radix_tree_gang_lookup(&dev->reada_extents, (void **)&re, + dev->reada_next >> PAGE_CACHE_SHIFT, 1); + } + if (ret == 0) { + spin_unlock(&fs_info->reada_lock); + return 0; + } + dev->reada_next = re->logical + re->blocksize; + kref_get(&re->refcnt); + + spin_unlock(&fs_info->reada_lock); + + /* + * find mirror num + */ + for (i = 0; i < re->nzones; ++i) { + if (re->zones[i]->device == dev) { + mirror_num = i + 1; + break; + } + } + logical = re->logical; + blocksize = re->blocksize; + + spin_lock(&re->lock); + if (re->scheduled_for == NULL) { + re->scheduled_for = dev; + need_kick = 1; + } + spin_unlock(&re->lock); + + reada_extent_put(fs_info, re); + + if (!need_kick) + return 0; + + atomic_inc(&dev->reada_in_flight); + ret = reada_tree_block_flagged(fs_info->extent_root, logical, blocksize, + mirror_num, &eb); + if (ret) + __readahead_hook(fs_info->extent_root, NULL, logical, ret); + else if (eb) + __readahead_hook(fs_info->extent_root, eb, eb->start, ret); + + if (eb) + free_extent_buffer(eb); + + return 1; + +} + +static void reada_start_machine_worker(struct btrfs_work *work) +{ + struct reada_machine_work *rmw; + struct btrfs_fs_info *fs_info; + + rmw = container_of(work, struct reada_machine_work, work); + fs_info = rmw->fs_info; + + kfree(rmw); + + __reada_start_machine(fs_info); +} + +static void __reada_start_machine(struct btrfs_fs_info *fs_info) +{ + struct btrfs_device *device; + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + u64 enqueued; + u64 total = 0; + int i; + + do { + enqueued = 0; + list_for_each_entry(device, &fs_devices->devices, dev_list) { + if (atomic_read(&device->reada_in_flight) < + MAX_IN_FLIGHT) + enqueued += reada_start_machine_dev(fs_info, + device); + } + total += enqueued; + } while (enqueued && total < 10000); + + if (enqueued == 0) + return; + + /* + * If everything is already in the cache, this is effectively single + * threaded. To a) not hold the caller for too long and b) to utilize + * more cores, we broke the loop above after 10000 iterations and now + * enqueue to workers to finish it. This will distribute the load to + * the cores. + */ + for (i = 0; i < 2; ++i) + reada_start_machine(fs_info); +} + +static void reada_start_machine(struct btrfs_fs_info *fs_info) +{ + struct reada_machine_work *rmw; + + rmw = kzalloc(sizeof(*rmw), GFP_NOFS); + if (!rmw) { + /* FIXME we cannot handle this properly right now */ + BUG(); + } + rmw->work.func = reada_start_machine_worker; + rmw->fs_info = fs_info; + + btrfs_queue_worker(&fs_info->readahead_workers, &rmw->work); +} + +#ifdef DEBUG +static void dump_devs(struct btrfs_fs_info *fs_info, int all) +{ + struct btrfs_device *device; + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + unsigned long index; + int ret; + int i; + int j; + int cnt; + + spin_lock(&fs_info->reada_lock); + list_for_each_entry(device, &fs_devices->devices, dev_list) { + printk(KERN_DEBUG "dev %lld has %d in flight\n", device->devid, + atomic_read(&device->reada_in_flight)); + index = 0; + while (1) { + struct reada_zone *zone; + ret = radix_tree_gang_lookup(&device->reada_zones, + (void **)&zone, index, 1); + if (ret == 0) + break; + printk(KERN_DEBUG " zone %llu-%llu elems %llu locked " + "%d devs", zone->start, zone->end, zone->elems, + zone->locked); + for (j = 0; j < zone->ndevs; ++j) { + printk(KERN_CONT " %lld", + zone->devs[j]->devid); + } + if (device->reada_curr_zone == zone) + printk(KERN_CONT " curr off %llu", + device->reada_next - zone->start); + printk(KERN_CONT "\n"); + index = (zone->end >> PAGE_CACHE_SHIFT) + 1; + } + cnt = 0; + index = 0; + while (all) { + struct reada_extent *re = NULL; + + ret = radix_tree_gang_lookup(&device->reada_extents, + (void **)&re, index, 1); + if (ret == 0) + break; + printk(KERN_DEBUG + " re: logical %llu size %u empty %d for %lld", + re->logical, re->blocksize, + list_empty(&re->extctl), re->scheduled_for ? + re->scheduled_for->devid : -1); + + for (i = 0; i < re->nzones; ++i) { + printk(KERN_CONT " zone %llu-%llu devs", + re->zones[i]->start, + re->zones[i]->end); + for (j = 0; j < re->zones[i]->ndevs; ++j) { + printk(KERN_CONT " %lld", + re->zones[i]->devs[j]->devid); + } + } + printk(KERN_CONT "\n"); + index = (re->logical >> PAGE_CACHE_SHIFT) + 1; + if (++cnt > 15) + break; + } + } + + index = 0; + cnt = 0; + while (all) { + struct reada_extent *re = NULL; + + ret = radix_tree_gang_lookup(&fs_info->reada_tree, (void **)&re, + index, 1); + if (ret == 0) + break; + if (!re->scheduled_for) { + index = (re->logical >> PAGE_CACHE_SHIFT) + 1; + continue; + } + printk(KERN_DEBUG + "re: logical %llu size %u list empty %d for %lld", + re->logical, re->blocksize, list_empty(&re->extctl), + re->scheduled_for ? re->scheduled_for->devid : -1); + for (i = 0; i < re->nzones; ++i) { + printk(KERN_CONT " zone %llu-%llu devs", + re->zones[i]->start, + re->zones[i]->end); + for (i = 0; i < re->nzones; ++i) { + printk(KERN_CONT " zone %llu-%llu devs", + re->zones[i]->start, + re->zones[i]->end); + for (j = 0; j < re->zones[i]->ndevs; ++j) { + printk(KERN_CONT " %lld", + re->zones[i]->devs[j]->devid); + } + } + } + printk(KERN_CONT "\n"); + index = (re->logical >> PAGE_CACHE_SHIFT) + 1; + } + spin_unlock(&fs_info->reada_lock); +} +#endif + +/* + * interface + */ +struct reada_control *btrfs_reada_add(struct btrfs_root *root, + struct btrfs_key *key_start, struct btrfs_key *key_end) +{ + struct reada_control *rc; + u64 start; + u64 generation; + int level; + struct extent_buffer *node; + static struct btrfs_key max_key = { + .objectid = (u64)-1, + .type = (u8)-1, + .offset = (u64)-1 + }; + + rc = kzalloc(sizeof(*rc), GFP_NOFS); + if (!rc) + return ERR_PTR(-ENOMEM); + + rc->root = root; + rc->key_start = *key_start; + rc->key_end = *key_end; + atomic_set(&rc->elems, 0); + init_waitqueue_head(&rc->wait); + kref_init(&rc->refcnt); + kref_get(&rc->refcnt); /* one ref for having elements */ + + node = btrfs_root_node(root); + start = node->start; + level = btrfs_header_level(node); + generation = btrfs_header_generation(node); + free_extent_buffer(node); + + reada_add_block(rc, start, &max_key, level, generation); + + reada_start_machine(root->fs_info); + + return rc; +} + +#ifdef DEBUG +int btrfs_reada_wait(void *handle) +{ + struct reada_control *rc = handle; + + while (atomic_read(&rc->elems)) { + wait_event_timeout(rc->wait, atomic_read(&rc->elems) == 0, + 5 * HZ); + dump_devs(rc->root->fs_info, rc->elems < 10 ? 1 : 0); + } + + dump_devs(rc->root->fs_info, rc->elems < 10 ? 1 : 0); + + kref_put(&rc->refcnt, reada_control_release); + + return 0; +} +#else +int btrfs_reada_wait(void *handle) +{ + struct reada_control *rc = handle; + + while (atomic_read(&rc->elems)) { + wait_event(rc->wait, atomic_read(&rc->elems) == 0); + } + + kref_put(&rc->refcnt, reada_control_release); + + return 0; +} +#endif + +void btrfs_reada_detach(void *handle) +{ + struct reada_control *rc = handle; + + kref_put(&rc->refcnt, reada_control_release); +} From 4bb31e928d1a47f5bd046ecb176b8eff7c589fc0 Mon Sep 17 00:00:00 2001 From: Arne Jansen Date: Fri, 10 Jun 2011 13:55:54 +0200 Subject: [PATCH 0495/1596] btrfs: hooks for readahead This adds the hooks needed for readahead. In the readpage_end_io_hook, the extent state is checked for the EXTENT_READAHEAD flag. Only in this case the readahead hook is called, to keep the impact on non-ra as low as possible. Additionally, a hook for a failed IO is added, otherwise readahead would wait indefinitely for the extent to finish. Changes for v2: - eliminate race condition Signed-off-by: Arne Jansen --- fs/btrfs/disk-io.c | 37 +++++++++++++++++++++++++++++++++++++ fs/btrfs/extent_io.c | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index fd28c40e9ec3..2151828aa142 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -609,11 +609,47 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, end = min_t(u64, eb->len, PAGE_CACHE_SIZE); end = eb->start + end - 1; err: + if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) { + clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags); + btree_readahead_hook(root, eb, eb->start, ret); + } + free_extent_buffer(eb); out: return ret; } +static int btree_io_failed_hook(struct bio *failed_bio, + struct page *page, u64 start, u64 end, + struct extent_state *state) +{ + struct extent_io_tree *tree; + unsigned long len; + struct extent_buffer *eb; + struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; + + tree = &BTRFS_I(page->mapping->host)->io_tree; + if (page->private == EXTENT_PAGE_PRIVATE) + goto out; + if (!page->private) + goto out; + + len = page->private >> 2; + WARN_ON(len == 0); + + eb = alloc_extent_buffer(tree, start, len, page); + if (eb == NULL) + goto out; + + if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) { + clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags); + btree_readahead_hook(root, eb, eb->start, -EIO); + } + +out: + return -EIO; /* we fixed nothing */ +} + static void end_workqueue_bio(struct bio *bio, int err) { struct end_io_wq *end_io_wq = bio->bi_private; @@ -3166,6 +3202,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) static struct extent_io_ops btree_extent_io_ops = { .write_cache_pages_lock_hook = btree_lock_page_hook, .readpage_end_io_hook = btree_readpage_end_io_hook, + .readpage_io_failed_hook = btree_io_failed_hook, .submit_bio_hook = btree_submit_bio_hook, /* note we're sharing with inode.c for the merge bio hook */ .merge_bio_hook = btrfs_merge_bio_hook, diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 823028e73cf8..deba714236d7 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1731,7 +1731,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) if (!uptodate && tree->ops && tree->ops->readpage_io_failed_hook) { ret = tree->ops->readpage_io_failed_hook(bio, page, - start, end, NULL); + start, end, state); if (ret == 0) { uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); From 7a26285eea8eb92e0088db011571d887d4551b0f Mon Sep 17 00:00:00 2001 From: Arne Jansen Date: Fri, 10 Jun 2011 12:39:23 +0200 Subject: [PATCH 0496/1596] btrfs: use readahead API for scrub Scrub uses a simple tree-enumeration to bring the relevant portions of the extent- and csum-tree into the page cache before starting the scrub-I/O. This is now replaced by using the new readahead-API. During readahead the scrub is being accounted as paused, so it won't hold off transaction commits. This change raises the average disk bandwith utilisation on my test volume from 70% to 90%. On another volume, the time for a test run went down from 89s to 43s. Changes v5: - reada1/2 are now of type struct reada_control * Signed-off-by: Arne Jansen --- fs/btrfs/scrub.c | 112 +++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 62 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index a8d03d5efb5d..f930f2776589 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -29,15 +29,12 @@ * any can be found. * * Future enhancements: - * - To enhance the performance, better read-ahead strategies for the - * extent-tree can be employed. * - In case an unrepairable extent is encountered, track which files are * affected and report them * - In case of a read error on files with nodatasum, map the file and read * the extent to trigger a writeback of the good copy * - track and record media errors, throw out bad devices * - add a mode to also read unallocated space - * - make the prefetch cancellable */ struct scrub_bio; @@ -741,13 +738,16 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, int slot; int i; u64 nstripes; - int start_stripe; struct extent_buffer *l; struct btrfs_key key; u64 physical; u64 logical; u64 generation; u64 mirror_num; + struct reada_control *reada1; + struct reada_control *reada2; + struct btrfs_key key_start; + struct btrfs_key key_end; u64 increment = map->stripe_len; u64 offset; @@ -779,81 +779,67 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, if (!path) return -ENOMEM; - path->reada = 2; path->search_commit_root = 1; path->skip_locking = 1; /* - * find all extents for each stripe and just read them to get - * them into the page cache - * FIXME: we can do better. build a more intelligent prefetching + * trigger the readahead for extent tree csum tree and wait for + * completion. During readahead, the scrub is officially paused + * to not hold off transaction commits */ logical = base + offset; - physical = map->stripes[num].physical; - ret = 0; - for (i = 0; i < nstripes; ++i) { - key.objectid = logical; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = (u64)0; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out_noplug; - - /* - * we might miss half an extent here, but that doesn't matter, - * as it's only the prefetch - */ - while (1) { - l = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(l)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out_noplug; - break; - } - btrfs_item_key_to_cpu(l, &key, slot); + wait_event(sdev->list_wait, + atomic_read(&sdev->in_flight) == 0); + atomic_inc(&fs_info->scrubs_paused); + wake_up(&fs_info->scrub_pause_wait); - if (key.objectid >= logical + map->stripe_len) - break; + /* FIXME it might be better to start readahead at commit root */ + key_start.objectid = logical; + key_start.type = BTRFS_EXTENT_ITEM_KEY; + key_start.offset = (u64)0; + key_end.objectid = base + offset + nstripes * increment; + key_end.type = BTRFS_EXTENT_ITEM_KEY; + key_end.offset = (u64)0; + reada1 = btrfs_reada_add(root, &key_start, &key_end); + + key_start.objectid = BTRFS_EXTENT_CSUM_OBJECTID; + key_start.type = BTRFS_EXTENT_CSUM_KEY; + key_start.offset = logical; + key_end.objectid = BTRFS_EXTENT_CSUM_OBJECTID; + key_end.type = BTRFS_EXTENT_CSUM_KEY; + key_end.offset = base + offset + nstripes * increment; + reada2 = btrfs_reada_add(csum_root, &key_start, &key_end); + + if (!IS_ERR(reada1)) + btrfs_reada_wait(reada1); + if (!IS_ERR(reada2)) + btrfs_reada_wait(reada2); - path->slots[0]++; - } - btrfs_release_path(path); - logical += increment; - physical += map->stripe_len; - cond_resched(); + mutex_lock(&fs_info->scrub_lock); + while (atomic_read(&fs_info->scrub_pause_req)) { + mutex_unlock(&fs_info->scrub_lock); + wait_event(fs_info->scrub_pause_wait, + atomic_read(&fs_info->scrub_pause_req) == 0); + mutex_lock(&fs_info->scrub_lock); } + atomic_dec(&fs_info->scrubs_paused); + mutex_unlock(&fs_info->scrub_lock); + wake_up(&fs_info->scrub_pause_wait); /* * collect all data csums for the stripe to avoid seeking during * the scrub. This might currently (crc32) end up to be about 1MB */ - start_stripe = 0; blk_start_plug(&plug); -again: - logical = base + offset + start_stripe * increment; - for (i = start_stripe; i < nstripes; ++i) { - ret = btrfs_lookup_csums_range(csum_root, logical, - logical + map->stripe_len - 1, - &sdev->csum_list, 1); - if (ret) - goto out; - logical += increment; - cond_resched(); - } /* * now find all extents for each stripe and scrub them */ - logical = base + offset + start_stripe * increment; - physical = map->stripes[num].physical + start_stripe * map->stripe_len; + logical = base + offset; + physical = map->stripes[num].physical; ret = 0; - for (i = start_stripe; i < nstripes; ++i) { + for (i = 0; i < nstripes; ++i) { /* * canceled? */ @@ -882,11 +868,14 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, atomic_dec(&fs_info->scrubs_paused); mutex_unlock(&fs_info->scrub_lock); wake_up(&fs_info->scrub_pause_wait); - scrub_free_csums(sdev); - start_stripe = i; - goto again; } + ret = btrfs_lookup_csums_range(csum_root, logical, + logical + map->stripe_len - 1, + &sdev->csum_list, 1); + if (ret) + goto out; + key.objectid = logical; key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = (u64)0; @@ -982,7 +971,6 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, out: blk_finish_plug(&plug); -out_noplug: btrfs_free_path(path); return ret < 0 ? ret : 0; } From 24f9e1f31471abbd2af62eb529deee90bad4c65c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 31 Aug 2011 15:47:16 +0900 Subject: [PATCH 0497/1596] ARM: EXYNOS4: Add USB EHCI device to ORIGEN board Signed-off-by: Pankaj Dubey Signed-off-by: Sachin Kamat [kgene.kim@samsung.com: re-ordering changes in Kconfig] Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/Kconfig | 2 ++ arch/arm/mach-exynos4/mach-origen.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 3ceefdbadd19..3034a736f823 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -224,7 +224,9 @@ config MACH_ORIGEN select S3C_DEV_RTC select S3C_DEV_WDT select S3C_DEV_HSMMC2 + select S5P_DEV_USB_EHCI select EXYNOS4_SETUP_SDHCI + select EXYNOS4_SETUP_USB_PHY help Machine support for ORIGEN based on Samsung EXYNOS4210 diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index ed59f86001ac..d101756ef7dc 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include @@ -79,10 +81,21 @@ static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = { .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, }; +/* USB EHCI */ +static struct s5p_ehci_platdata origen_ehci_pdata; + +static void __init origen_ehci_init(void) +{ + struct s5p_ehci_platdata *pdata = &origen_ehci_pdata; + + s5p_ehci_set_platdata(pdata); +} + static struct platform_device *origen_devices[] __initdata = { &s3c_device_hsmmc2, &s3c_device_rtc, &s3c_device_wdt, + &s5p_device_ehci, }; static void __init origen_map_io(void) @@ -95,6 +108,10 @@ static void __init origen_map_io(void) static void __init origen_machine_init(void) { s3c_sdhci2_set_platdata(&origen_hsmmc2_pdata); + + origen_ehci_init(); + clk_xusbxti.rate = 24000000; + platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); } From 6f8eb324a395da5bd0c0b113944f2906272e14bd Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 31 Aug 2011 15:52:27 +0900 Subject: [PATCH 0498/1596] ARM: EXYNOS4: Add FIMC device on ORIGEN board This patch adds definitions to enable support for s5p-fimc driver on ORIGEN board. Signed-off-by: Sachin Kamat [kgene.kim@samsung.com: re-ordering changes] Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/Kconfig | 4 ++++ arch/arm/mach-exynos4/mach-origen.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 3034a736f823..9c920b2acc36 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -224,6 +224,10 @@ config MACH_ORIGEN select S3C_DEV_RTC select S3C_DEV_WDT select S3C_DEV_HSMMC2 + select S5P_DEV_FIMC0 + select S5P_DEV_FIMC1 + select S5P_DEV_FIMC2 + select S5P_DEV_FIMC3 select S5P_DEV_USB_EHCI select EXYNOS4_SETUP_SDHCI select EXYNOS4_SETUP_USB_PHY diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index d101756ef7dc..7ac71878767b 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -96,6 +96,10 @@ static struct platform_device *origen_devices[] __initdata = { &s3c_device_rtc, &s3c_device_wdt, &s5p_device_ehci, + &s5p_device_fimc0, + &s5p_device_fimc1, + &s5p_device_fimc2, + &s5p_device_fimc3, }; static void __init origen_map_io(void) From 9edff0f79f5b98e6abfabfa27b31d155e3c994e1 Mon Sep 17 00:00:00 2001 From: Giridhar Maruthy Date: Wed, 31 Aug 2011 15:58:52 +0900 Subject: [PATCH 0499/1596] ARM: EXYNOS4: Add PWM backlight support on ORIGEN This patch adds support for LCD backlight using PWM timer on ORIGEN board. Signed-off-by: Giridhar Maruthy Signed-off-by: Sachin Kamat Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/Kconfig | 2 ++ arch/arm/mach-exynos4/mach-origen.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 9c920b2acc36..86cf4fd47b35 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -229,6 +229,8 @@ config MACH_ORIGEN select S5P_DEV_FIMC2 select S5P_DEV_FIMC3 select S5P_DEV_USB_EHCI + select SAMSUNG_DEV_BACKLIGHT + select SAMSUNG_DEV_PWM select EXYNOS4_SETUP_SDHCI select EXYNOS4_SETUP_USB_PHY help diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index 7ac71878767b..937db75688d0 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,8 @@ #include #include #include +#include +#include #include @@ -102,6 +105,17 @@ static struct platform_device *origen_devices[] __initdata = { &s5p_device_fimc3, }; +/* LCD Backlight data */ +static struct samsung_bl_gpio_info origen_bl_gpio_info = { + .no = EXYNOS4_GPD0(0), + .func = S3C_GPIO_SFN(2), +}; + +static struct platform_pwm_backlight_data origen_bl_data = { + .pwm_id = 0, + .pwm_period_ns = 1000, +}; + static void __init origen_map_io(void) { s5p_init_io(NULL, 0, S5P_VA_CHIPID); @@ -117,6 +131,8 @@ static void __init origen_machine_init(void) clk_xusbxti.rate = 24000000; platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); + + samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); } MACHINE_START(ORIGEN, "ORIGEN") From 92e41efd73918d28ad48a937489e6f2a02140057 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Wed, 31 Aug 2011 16:01:15 +0900 Subject: [PATCH 0500/1596] ARM: EXYNOS4: Fix sdhci card detection for ORIGEN Fix incorrect value of cd_type field in platform data for sdhci device. Signed-off-by: Tushar Behera Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/mach-origen.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index 937db75688d0..0e3b81634c24 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -78,9 +78,7 @@ static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { }; static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = { - .cd_type = S3C_SDHCI_CD_GPIO, - .ext_cd_gpio = EXYNOS4_GPK2(2), - .ext_cd_gpio_invert = 1, + .cd_type = S3C_SDHCI_CD_INTERNAL, .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, }; From cf1dad9d7f14ddf555baa0fcc82d17d5f29d3ae2 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Wed, 31 Aug 2011 16:57:37 +0900 Subject: [PATCH 0501/1596] ARM: EXYNOS4: Add support for secondary MMC port on ORIGEN Secondary MMC port on ORIGEN is connected to sdhci instance 0. Support for secondary MMC port is extended by registering sdhci instance 0. Since sdhci instance 2 can contain a bootable media, sdhci instance 0 is registered after instance 2. Signed-off-by: Tushar Behera [kgene.kim@samsung.com: Added comments in registering sdhci] Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/Kconfig | 1 + arch/arm/mach-exynos4/mach-origen.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 86cf4fd47b35..00c645426d3f 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -223,6 +223,7 @@ config MACH_ORIGEN select CPU_EXYNOS4210 select S3C_DEV_RTC select S3C_DEV_WDT + select S3C_DEV_HSMMC select S3C_DEV_HSMMC2 select S5P_DEV_FIMC0 select S5P_DEV_FIMC1 diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index 0e3b81634c24..cd5195f93548 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -77,6 +77,11 @@ static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { }, }; +static struct s3c_sdhci_platdata origen_hsmmc0_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_INTERNAL, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +}; + static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = { .cd_type = S3C_SDHCI_CD_INTERNAL, .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, @@ -94,6 +99,7 @@ static void __init origen_ehci_init(void) static struct platform_device *origen_devices[] __initdata = { &s3c_device_hsmmc2, + &s3c_device_hsmmc0, &s3c_device_rtc, &s3c_device_wdt, &s5p_device_ehci, @@ -123,7 +129,12 @@ static void __init origen_map_io(void) static void __init origen_machine_init(void) { + /* + * Since sdhci instance 2 can contain a bootable media, + * sdhci instance 0 is registered after instance 2. + */ s3c_sdhci2_set_platdata(&origen_hsmmc2_pdata); + s3c_sdhci0_set_platdata(&origen_hsmmc0_pdata); origen_ehci_init(); clk_xusbxti.rate = 24000000; From c86cfdd012498ddab2b2eb23fad201637a77acf4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 16 Sep 2011 21:41:25 +0900 Subject: [PATCH 0502/1596] ARM: EXYNOS4: Add keypad support for ORIGEN This patch adds keypad support for ORIGEN board as GPIO keys. Signed-off-by: Sachin Kamat Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/mach-origen.c | 58 +++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index cd5195f93548..3d67140aaea9 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -97,6 +98,62 @@ static void __init origen_ehci_init(void) s5p_ehci_set_platdata(pdata); } +static struct gpio_keys_button origen_gpio_keys_table[] = { + { + .code = KEY_MENU, + .gpio = EXYNOS4_GPX1(5), + .desc = "gpio-keys: KEY_MENU", + .type = EV_KEY, + .active_low = 1, + .wakeup = 1, + .debounce_interval = 1, + }, { + .code = KEY_HOME, + .gpio = EXYNOS4_GPX1(6), + .desc = "gpio-keys: KEY_HOME", + .type = EV_KEY, + .active_low = 1, + .wakeup = 1, + .debounce_interval = 1, + }, { + .code = KEY_BACK, + .gpio = EXYNOS4_GPX1(7), + .desc = "gpio-keys: KEY_BACK", + .type = EV_KEY, + .active_low = 1, + .wakeup = 1, + .debounce_interval = 1, + }, { + .code = KEY_UP, + .gpio = EXYNOS4_GPX2(0), + .desc = "gpio-keys: KEY_UP", + .type = EV_KEY, + .active_low = 1, + .wakeup = 1, + .debounce_interval = 1, + }, { + .code = KEY_DOWN, + .gpio = EXYNOS4_GPX2(1), + .desc = "gpio-keys: KEY_DOWN", + .type = EV_KEY, + .active_low = 1, + .wakeup = 1, + .debounce_interval = 1, + }, +}; + +static struct gpio_keys_platform_data origen_gpio_keys_data = { + .buttons = origen_gpio_keys_table, + .nbuttons = ARRAY_SIZE(origen_gpio_keys_table), +}; + +static struct platform_device origen_device_gpiokeys = { + .name = "gpio-keys", + .dev = { + .platform_data = &origen_gpio_keys_data, + }, +}; + static struct platform_device *origen_devices[] __initdata = { &s3c_device_hsmmc2, &s3c_device_hsmmc0, @@ -107,6 +164,7 @@ static struct platform_device *origen_devices[] __initdata = { &s5p_device_fimc1, &s5p_device_fimc2, &s5p_device_fimc3, + &origen_device_gpiokeys, }; /* LCD Backlight data */ From 6ca3f8bdf8253504426935c97cabb44bdc6f5888 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Sat, 17 Sep 2011 11:42:43 +0900 Subject: [PATCH 0503/1596] ARM: EXYNOS4: Add HDMI support for ORIGEN This patch adds HDMI (TVout) support for ORIGEN board. Signed-off-by: Sachin Kamat Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/Kconfig | 2 ++ arch/arm/mach-exynos4/mach-origen.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 00c645426d3f..257dbaaf149b 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -229,7 +229,9 @@ config MACH_ORIGEN select S5P_DEV_FIMC1 select S5P_DEV_FIMC2 select S5P_DEV_FIMC3 + select S5P_DEV_I2C_HDMIPHY select S5P_DEV_USB_EHCI + select S5P_DEV_TV select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_PWM select EXYNOS4_SETUP_SDHCI diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index 3d67140aaea9..c8121fcf198d 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -164,6 +164,9 @@ static struct platform_device *origen_devices[] __initdata = { &s5p_device_fimc1, &s5p_device_fimc2, &s5p_device_fimc3, + &s5p_device_hdmi, + &s5p_device_i2c_hdmiphy, + &s5p_device_mixer, &origen_device_gpiokeys, }; @@ -197,6 +200,8 @@ static void __init origen_machine_init(void) origen_ehci_init(); clk_xusbxti.rate = 24000000; + s5p_i2c_hdmiphy_set_platdata(NULL); + platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); From c8e28ce049faa53a470c132893abbc9f2bde9420 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sun, 23 Jan 2011 10:07:47 -0600 Subject: [PATCH 0504/1596] writeback: account per-bdi accumulated dirtied pages Introduce the BDI_DIRTIED counter. It will be used for estimating the bdi's dirty bandwidth. CC: Jan Kara CC: Michael Rubin CC: Peter Zijlstra Signed-off-by: Wu Fengguang --- include/linux/backing-dev.h | 1 + mm/backing-dev.c | 2 ++ mm/page-writeback.c | 1 + 3 files changed, 4 insertions(+) diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 3b2f9cb82986..9ca241a70c49 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -40,6 +40,7 @@ typedef int (congested_fn)(void *, int); enum bdi_stat_item { BDI_RECLAIMABLE, BDI_WRITEBACK, + BDI_DIRTIED, BDI_WRITTEN, NR_BDI_STAT_ITEMS }; diff --git a/mm/backing-dev.c b/mm/backing-dev.c index a87da524a4a0..fea7e6efd1d7 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -97,6 +97,7 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v) "BdiDirtyThresh: %10lu kB\n" "DirtyThresh: %10lu kB\n" "BackgroundThresh: %10lu kB\n" + "BdiDirtied: %10lu kB\n" "BdiWritten: %10lu kB\n" "BdiWriteBandwidth: %10lu kBps\n" "b_dirty: %10lu\n" @@ -109,6 +110,7 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v) K(bdi_thresh), K(dirty_thresh), K(background_thresh), + (unsigned long) K(bdi_stat(bdi, BDI_DIRTIED)), (unsigned long) K(bdi_stat(bdi, BDI_WRITTEN)), (unsigned long) K(bdi->write_bandwidth), nr_dirty, diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 0e309cd1b5b9..0e6dd5c2ed31 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1322,6 +1322,7 @@ void account_page_dirtied(struct page *page, struct address_space *mapping) __inc_zone_page_state(page, NR_FILE_DIRTY); __inc_zone_page_state(page, NR_DIRTIED); __inc_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE); + __inc_bdi_stat(mapping->backing_dev_info, BDI_DIRTIED); task_dirty_inc(current); task_io_account_write(PAGE_CACHE_SIZE); } From 6c14ae1e92c77eabd3e7527cf2e7836cde8b8487 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 2 Mar 2011 16:04:18 -0600 Subject: [PATCH 0505/1596] writeback: dirty position control bdi_position_ratio() provides a scale factor to bdi->dirty_ratelimit, so that the resulted task rate limit can drive the dirty pages back to the global/bdi setpoints. Old scheme is, | free run area | throttle area ----------------------------------------+----------------------------> thresh^ dirty pages New scheme is, ^ task rate limit | | * | * | * |[free run] * [smooth throttled] | * | * | * ..bdi->dirty_ratelimit..........* | . * | . * | . * | . * | . * +-------------------------------.-----------------------*------------> setpoint^ limit^ dirty pages The slope of the bdi control line should be 1) large enough to pull the dirty pages to setpoint reasonably fast 2) small enough to avoid big fluctuations in the resulted pos_ratio and hence task ratelimit Since the fluctuation range of the bdi dirty pages is typically observed to be within 1-second worth of data, the bdi control line's slope is selected to be a linear function of bdi write bandwidth, so that it can adapt to slow/fast storage devices well. Assume the bdi control line pos_ratio = 1.0 + k * (dirty - bdi_setpoint) where k is the negative slope. If targeting for 12.5% fluctuation range in pos_ratio when dirty pages are fluctuating in range [bdi_setpoint - write_bw/2, bdi_setpoint + write_bw/2], we get slope k = - 1 / (8 * write_bw) Let pos_ratio(x_intercept) = 0, we get the parameter used in code: x_intercept = bdi_setpoint + 8 * write_bw The global/bdi slopes are nicely complementing each other when the system has only one major bdi (indicated by bdi_thresh ~= thresh): 1) slope of global control line => scaling to the control scope size 2) slope of main bdi control line => scaling to the writeout bandwidth so that - in memory tight systems, (1) becomes strong enough to squeeze dirty pages inside the control scope - in large memory systems where the "gravity" of (1) for pulling the dirty pages to setpoint is too weak, (2) can back (1) up and drive dirty pages to bdi_setpoint ~= setpoint reasonably fast. Unfortunately in JBOD setups, the fluctuation range of bdi threshold is related to memory size due to the interferences between disks. In this case, the bdi slope will be weighted sum of write_bw and bdi_thresh. Given equations span = x_intercept - bdi_setpoint k = df/dx = - 1 / span and the extremum values span = bdi_thresh dx = bdi_thresh we get df = - dx / span = - 1.0 That means, when bdi_dirty deviates bdi_thresh up, pos_ratio and hence task ratelimit will fluctuate by -100%. peter: use 3rd order polynomial for the global control line CC: Peter Zijlstra Acked-by: Jan Kara Signed-off-by: Wu Fengguang --- mm/page-writeback.c | 191 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 1 deletion(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 0e6dd5c2ed31..c16ddd8f5cb6 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -46,6 +46,8 @@ */ #define BANDWIDTH_INTERVAL max(HZ/5, 1) +#define RATELIMIT_CALC_SHIFT 10 + /* * After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited * will look to see if it needs to force writeback or throttling. @@ -411,6 +413,12 @@ unsigned long determine_dirtyable_memory(void) return x + 1; /* Ensure that we never return 0 */ } +static unsigned long dirty_freerun_ceiling(unsigned long thresh, + unsigned long bg_thresh) +{ + return (thresh + bg_thresh) / 2; +} + static unsigned long hard_dirty_limit(unsigned long thresh) { return max(thresh, global_dirty_limit); @@ -495,6 +503,184 @@ unsigned long bdi_dirty_limit(struct backing_dev_info *bdi, unsigned long dirty) return bdi_dirty; } +/* + * Dirty position control. + * + * (o) global/bdi setpoints + * + * We want the dirty pages be balanced around the global/bdi setpoints. + * When the number of dirty pages is higher/lower than the setpoint, the + * dirty position control ratio (and hence task dirty ratelimit) will be + * decreased/increased to bring the dirty pages back to the setpoint. + * + * pos_ratio = 1 << RATELIMIT_CALC_SHIFT + * + * if (dirty < setpoint) scale up pos_ratio + * if (dirty > setpoint) scale down pos_ratio + * + * if (bdi_dirty < bdi_setpoint) scale up pos_ratio + * if (bdi_dirty > bdi_setpoint) scale down pos_ratio + * + * task_ratelimit = dirty_ratelimit * pos_ratio >> RATELIMIT_CALC_SHIFT + * + * (o) global control line + * + * ^ pos_ratio + * | + * | |<===== global dirty control scope ======>| + * 2.0 .............* + * | .* + * | . * + * | . * + * | . * + * | . * + * | . * + * 1.0 ................................* + * | . . * + * | . . * + * | . . * + * | . . * + * | . . * + * 0 +------------.------------------.----------------------*-------------> + * freerun^ setpoint^ limit^ dirty pages + * + * (o) bdi control line + * + * ^ pos_ratio + * | + * | * + * | * + * | * + * | * + * | * |<=========== span ============>| + * 1.0 .......................* + * | . * + * | . * + * | . * + * | . * + * | . * + * | . * + * | . * + * | . * + * | . * + * | . * + * | . * + * 1/4 ...............................................* * * * * * * * * * * * + * | . . + * | . . + * | . . + * 0 +----------------------.-------------------------------.-------------> + * bdi_setpoint^ x_intercept^ + * + * The bdi control line won't drop below pos_ratio=1/4, so that bdi_dirty can + * be smoothly throttled down to normal if it starts high in situations like + * - start writing to a slow SD card and a fast disk at the same time. The SD + * card's bdi_dirty may rush to many times higher than bdi_setpoint. + * - the bdi dirty thresh drops quickly due to change of JBOD workload + */ +static unsigned long bdi_position_ratio(struct backing_dev_info *bdi, + unsigned long thresh, + unsigned long bg_thresh, + unsigned long dirty, + unsigned long bdi_thresh, + unsigned long bdi_dirty) +{ + unsigned long write_bw = bdi->avg_write_bandwidth; + unsigned long freerun = dirty_freerun_ceiling(thresh, bg_thresh); + unsigned long limit = hard_dirty_limit(thresh); + unsigned long x_intercept; + unsigned long setpoint; /* dirty pages' target balance point */ + unsigned long bdi_setpoint; + unsigned long span; + long long pos_ratio; /* for scaling up/down the rate limit */ + long x; + + if (unlikely(dirty >= limit)) + return 0; + + /* + * global setpoint + * + * setpoint - dirty 3 + * f(dirty) := 1.0 + (----------------) + * limit - setpoint + * + * it's a 3rd order polynomial that subjects to + * + * (1) f(freerun) = 2.0 => rampup dirty_ratelimit reasonably fast + * (2) f(setpoint) = 1.0 => the balance point + * (3) f(limit) = 0 => the hard limit + * (4) df/dx <= 0 => negative feedback control + * (5) the closer to setpoint, the smaller |df/dx| (and the reverse) + * => fast response on large errors; small oscillation near setpoint + */ + setpoint = (freerun + limit) / 2; + x = div_s64((setpoint - dirty) << RATELIMIT_CALC_SHIFT, + limit - setpoint + 1); + pos_ratio = x; + pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT; + pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT; + pos_ratio += 1 << RATELIMIT_CALC_SHIFT; + + /* + * We have computed basic pos_ratio above based on global situation. If + * the bdi is over/under its share of dirty pages, we want to scale + * pos_ratio further down/up. That is done by the following mechanism. + */ + + /* + * bdi setpoint + * + * f(bdi_dirty) := 1.0 + k * (bdi_dirty - bdi_setpoint) + * + * x_intercept - bdi_dirty + * := -------------------------- + * x_intercept - bdi_setpoint + * + * The main bdi control line is a linear function that subjects to + * + * (1) f(bdi_setpoint) = 1.0 + * (2) k = - 1 / (8 * write_bw) (in single bdi case) + * or equally: x_intercept = bdi_setpoint + 8 * write_bw + * + * For single bdi case, the dirty pages are observed to fluctuate + * regularly within range + * [bdi_setpoint - write_bw/2, bdi_setpoint + write_bw/2] + * for various filesystems, where (2) can yield in a reasonable 12.5% + * fluctuation range for pos_ratio. + * + * For JBOD case, bdi_thresh (not bdi_dirty!) could fluctuate up to its + * own size, so move the slope over accordingly and choose a slope that + * yields 100% pos_ratio fluctuation on suddenly doubled bdi_thresh. + */ + if (unlikely(bdi_thresh > thresh)) + bdi_thresh = thresh; + /* + * scale global setpoint to bdi's: + * bdi_setpoint = setpoint * bdi_thresh / thresh + */ + x = div_u64((u64)bdi_thresh << 16, thresh + 1); + bdi_setpoint = setpoint * (u64)x >> 16; + /* + * Use span=(8*write_bw) in single bdi case as indicated by + * (thresh - bdi_thresh ~= 0) and transit to bdi_thresh in JBOD case. + * + * bdi_thresh thresh - bdi_thresh + * span = ---------- * (8 * write_bw) + ------------------- * bdi_thresh + * thresh thresh + */ + span = (thresh - bdi_thresh + 8 * write_bw) * (u64)x >> 16; + x_intercept = bdi_setpoint + span; + + if (bdi_dirty < x_intercept - span / 4) { + pos_ratio *= x_intercept - bdi_dirty; + do_div(pos_ratio, x_intercept - bdi_setpoint + 1); + } else + pos_ratio /= 4; + + return pos_ratio; +} + static void bdi_update_write_bandwidth(struct backing_dev_info *bdi, unsigned long elapsed, unsigned long written) @@ -655,6 +841,7 @@ static void balance_dirty_pages(struct address_space *mapping, unsigned long nr_reclaimable, bdi_nr_reclaimable; unsigned long nr_dirty; /* = file_dirty + writeback + unstable_nfs */ unsigned long bdi_dirty; + unsigned long freerun; unsigned long background_thresh; unsigned long dirty_thresh; unsigned long bdi_thresh; @@ -679,7 +866,9 @@ static void balance_dirty_pages(struct address_space *mapping, * catch-up. This avoids (excessively) small writeouts * when the bdi limits are ramping up. */ - if (nr_dirty <= (background_thresh + dirty_thresh) / 2) + freerun = dirty_freerun_ceiling(dirty_thresh, + background_thresh); + if (nr_dirty <= freerun) break; bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh); From af6a311384bce6c88e15c80ab22ab051a918b4eb Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 3 Oct 2011 20:46:17 -0600 Subject: [PATCH 0506/1596] writeback: add bg_threshold parameter to __bdi_update_bandwidth() No behavior change. Signed-off-by: Wu Fengguang --- fs/fs-writeback.c | 2 +- include/linux/writeback.h | 1 + mm/page-writeback.c | 11 +++++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 04cf3b91e501..28076562ada0 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -675,7 +675,7 @@ static inline bool over_bground_thresh(void) static void wb_update_bandwidth(struct bdi_writeback *wb, unsigned long start_time) { - __bdi_update_bandwidth(wb->bdi, 0, 0, 0, 0, start_time); + __bdi_update_bandwidth(wb->bdi, 0, 0, 0, 0, 0, start_time); } /* diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 2b8963ff0f35..ddb4652cb337 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -143,6 +143,7 @@ unsigned long bdi_dirty_limit(struct backing_dev_info *bdi, void __bdi_update_bandwidth(struct backing_dev_info *bdi, unsigned long thresh, + unsigned long bg_thresh, unsigned long dirty, unsigned long bdi_thresh, unsigned long bdi_dirty, diff --git a/mm/page-writeback.c b/mm/page-writeback.c index c16ddd8f5cb6..4b954c9fe846 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -779,6 +779,7 @@ static void global_update_bandwidth(unsigned long thresh, void __bdi_update_bandwidth(struct backing_dev_info *bdi, unsigned long thresh, + unsigned long bg_thresh, unsigned long dirty, unsigned long bdi_thresh, unsigned long bdi_dirty, @@ -815,6 +816,7 @@ void __bdi_update_bandwidth(struct backing_dev_info *bdi, static void bdi_update_bandwidth(struct backing_dev_info *bdi, unsigned long thresh, + unsigned long bg_thresh, unsigned long dirty, unsigned long bdi_thresh, unsigned long bdi_dirty, @@ -823,8 +825,8 @@ static void bdi_update_bandwidth(struct backing_dev_info *bdi, if (time_is_after_eq_jiffies(bdi->bw_time_stamp + BANDWIDTH_INTERVAL)) return; spin_lock(&bdi->wb.list_lock); - __bdi_update_bandwidth(bdi, thresh, dirty, bdi_thresh, bdi_dirty, - start_time); + __bdi_update_bandwidth(bdi, thresh, bg_thresh, dirty, + bdi_thresh, bdi_dirty, start_time); spin_unlock(&bdi->wb.list_lock); } @@ -912,8 +914,9 @@ static void balance_dirty_pages(struct address_space *mapping, if (!bdi->dirty_exceeded) bdi->dirty_exceeded = 1; - bdi_update_bandwidth(bdi, dirty_thresh, nr_dirty, - bdi_thresh, bdi_dirty, start_time); + bdi_update_bandwidth(bdi, dirty_thresh, background_thresh, + nr_dirty, bdi_thresh, bdi_dirty, + start_time); /* Note: nr_reclaimable denotes nr_dirty + nr_unstable. * Unstable writes are a feature of certain networked From be3ffa276446e1b691a2bf84e7621e5a6fb49db9 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sun, 12 Jun 2011 10:51:31 -0600 Subject: [PATCH 0507/1596] writeback: dirty rate control It's all about bdi->dirty_ratelimit, which aims to be (write_bw / N) when there are N dd tasks. On write() syscall, use bdi->dirty_ratelimit ============================================ balance_dirty_pages(pages_dirtied) { task_ratelimit = bdi->dirty_ratelimit * bdi_position_ratio(); pause = pages_dirtied / task_ratelimit; sleep(pause); } On every 200ms, update bdi->dirty_ratelimit =========================================== bdi_update_dirty_ratelimit() { task_ratelimit = bdi->dirty_ratelimit * bdi_position_ratio(); balanced_dirty_ratelimit = task_ratelimit * write_bw / dirty_rate; bdi->dirty_ratelimit = balanced_dirty_ratelimit } Estimation of balanced bdi->dirty_ratelimit =========================================== balanced task_ratelimit ----------------------- balance_dirty_pages() needs to throttle tasks dirtying pages such that the total amount of dirty pages stays below the specified dirty limit in order to avoid memory deadlocks. Furthermore we desire fairness in that tasks get throttled proportionally to the amount of pages they dirty. IOW we want to throttle tasks such that we match the dirty rate to the writeout bandwidth, this yields a stable amount of dirty pages: dirty_rate == write_bw (1) The fairness requirement gives us: task_ratelimit = balanced_dirty_ratelimit == write_bw / N (2) where N is the number of dd tasks. We don't know N beforehand, but still can estimate balanced_dirty_ratelimit within 200ms. Start by throttling each dd task at rate task_ratelimit = task_ratelimit_0 (3) (any non-zero initial value is OK) After 200ms, we measured dirty_rate = # of pages dirtied by all dd's / 200ms write_bw = # of pages written to the disk / 200ms For the aggressive dd dirtiers, the equality holds dirty_rate == N * task_rate == N * task_ratelimit_0 (4) Or task_ratelimit_0 == dirty_rate / N (5) Now we conclude that the balanced task ratelimit can be estimated by write_bw balanced_dirty_ratelimit = task_ratelimit_0 * ---------- (6) dirty_rate Because with (4) and (5) we can get the desired equality (1): write_bw balanced_dirty_ratelimit == (dirty_rate / N) * ---------- dirty_rate == write_bw / N Then using the balanced task ratelimit we can compute task pause times like: task_pause = task->nr_dirtied / task_ratelimit task_ratelimit with position control ------------------------------------ However, while the above gives us means of matching the dirty rate to the writeout bandwidth, it at best provides us with a stable dirty page count (assuming a static system). In order to control the dirty page count such that it is high enough to provide performance, but does not exceed the specified limit we need another control. The dirty position control works by extending (2) to task_ratelimit = balanced_dirty_ratelimit * pos_ratio (7) where pos_ratio is a negative feedback function that subjects to 1) f(setpoint) = 1.0 2) df/dx < 0 That is, if the dirty pages are ABOVE the setpoint, we throttle each task a bit more HEAVY than balanced_dirty_ratelimit, so that the dirty pages are created less fast than they are cleaned, thus DROP to the setpoints (and the reverse). Based on (7) and the assumption that both dirty_ratelimit and pos_ratio remains CONSTANT for the past 200ms, we get task_ratelimit_0 = balanced_dirty_ratelimit * pos_ratio (8) Putting (8) into (6), we get the formula used in bdi_update_dirty_ratelimit(): write_bw balanced_dirty_ratelimit *= pos_ratio * ---------- (9) dirty_rate Signed-off-by: Wu Fengguang --- include/linux/backing-dev.h | 7 ++++ mm/backing-dev.c | 1 + mm/page-writeback.c | 83 ++++++++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 9ca241a70c49..dff0ff78e878 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -75,10 +75,17 @@ struct backing_dev_info { struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS]; unsigned long bw_time_stamp; /* last time write bw is updated */ + unsigned long dirtied_stamp; unsigned long written_stamp; /* pages written at bw_time_stamp */ unsigned long write_bandwidth; /* the estimated write bandwidth */ unsigned long avg_write_bandwidth; /* further smoothed write bw */ + /* + * The base dirty throttle rate, re-calculated on every 200ms. + * All the bdi tasks' dirty rate will be curbed under it. + */ + unsigned long dirty_ratelimit; + struct prop_local_percpu completions; int dirty_exceeded; diff --git a/mm/backing-dev.c b/mm/backing-dev.c index fea7e6efd1d7..ba20f94cde93 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -686,6 +686,7 @@ int bdi_init(struct backing_dev_info *bdi) bdi->bw_time_stamp = jiffies; bdi->written_stamp = 0; + bdi->dirty_ratelimit = INIT_BW; bdi->write_bandwidth = INIT_BW; bdi->avg_write_bandwidth = INIT_BW; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 4b954c9fe846..1721b6523c04 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -777,6 +777,79 @@ static void global_update_bandwidth(unsigned long thresh, spin_unlock(&dirty_lock); } +/* + * Maintain bdi->dirty_ratelimit, the base dirty throttle rate. + * + * Normal bdi tasks will be curbed at or below it in long term. + * Obviously it should be around (write_bw / N) when there are N dd tasks. + */ +static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi, + unsigned long thresh, + unsigned long bg_thresh, + unsigned long dirty, + unsigned long bdi_thresh, + unsigned long bdi_dirty, + unsigned long dirtied, + unsigned long elapsed) +{ + unsigned long write_bw = bdi->avg_write_bandwidth; + unsigned long dirty_ratelimit = bdi->dirty_ratelimit; + unsigned long dirty_rate; + unsigned long task_ratelimit; + unsigned long balanced_dirty_ratelimit; + unsigned long pos_ratio; + + /* + * The dirty rate will match the writeout rate in long term, except + * when dirty pages are truncated by userspace or re-dirtied by FS. + */ + dirty_rate = (dirtied - bdi->dirtied_stamp) * HZ / elapsed; + + pos_ratio = bdi_position_ratio(bdi, thresh, bg_thresh, dirty, + bdi_thresh, bdi_dirty); + /* + * task_ratelimit reflects each dd's dirty rate for the past 200ms. + */ + task_ratelimit = (u64)dirty_ratelimit * + pos_ratio >> RATELIMIT_CALC_SHIFT; + task_ratelimit++; /* it helps rampup dirty_ratelimit from tiny values */ + + /* + * A linear estimation of the "balanced" throttle rate. The theory is, + * if there are N dd tasks, each throttled at task_ratelimit, the bdi's + * dirty_rate will be measured to be (N * task_ratelimit). So the below + * formula will yield the balanced rate limit (write_bw / N). + * + * Note that the expanded form is not a pure rate feedback: + * rate_(i+1) = rate_(i) * (write_bw / dirty_rate) (1) + * but also takes pos_ratio into account: + * rate_(i+1) = rate_(i) * (write_bw / dirty_rate) * pos_ratio (2) + * + * (1) is not realistic because pos_ratio also takes part in balancing + * the dirty rate. Consider the state + * pos_ratio = 0.5 (3) + * rate = 2 * (write_bw / N) (4) + * If (1) is used, it will stuck in that state! Because each dd will + * be throttled at + * task_ratelimit = pos_ratio * rate = (write_bw / N) (5) + * yielding + * dirty_rate = N * task_ratelimit = write_bw (6) + * put (6) into (1) we get + * rate_(i+1) = rate_(i) (7) + * + * So we end up using (2) to always keep + * rate_(i+1) ~= (write_bw / N) (8) + * regardless of the value of pos_ratio. As long as (8) is satisfied, + * pos_ratio is able to drive itself to 1.0, which is not only where + * the dirty count meet the setpoint, but also where the slope of + * pos_ratio is most flat and hence task_ratelimit is least fluctuated. + */ + balanced_dirty_ratelimit = div_u64((u64)task_ratelimit * write_bw, + dirty_rate | 1); + + bdi->dirty_ratelimit = max(balanced_dirty_ratelimit, 1UL); +} + void __bdi_update_bandwidth(struct backing_dev_info *bdi, unsigned long thresh, unsigned long bg_thresh, @@ -787,6 +860,7 @@ void __bdi_update_bandwidth(struct backing_dev_info *bdi, { unsigned long now = jiffies; unsigned long elapsed = now - bdi->bw_time_stamp; + unsigned long dirtied; unsigned long written; /* @@ -795,6 +869,7 @@ void __bdi_update_bandwidth(struct backing_dev_info *bdi, if (elapsed < BANDWIDTH_INTERVAL) return; + dirtied = percpu_counter_read(&bdi->bdi_stat[BDI_DIRTIED]); written = percpu_counter_read(&bdi->bdi_stat[BDI_WRITTEN]); /* @@ -804,12 +879,16 @@ void __bdi_update_bandwidth(struct backing_dev_info *bdi, if (elapsed > HZ && time_before(bdi->bw_time_stamp, start_time)) goto snapshot; - if (thresh) + if (thresh) { global_update_bandwidth(thresh, dirty, now); - + bdi_update_dirty_ratelimit(bdi, thresh, bg_thresh, dirty, + bdi_thresh, bdi_dirty, + dirtied, elapsed); + } bdi_update_write_bandwidth(bdi, elapsed, written); snapshot: + bdi->dirtied_stamp = dirtied; bdi->written_stamp = written; bdi->bw_time_stamp = now; } From 7381131cbcf7e15d201a0ffd782a4698efe4e740 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 26 Aug 2011 15:53:24 -0600 Subject: [PATCH 0508/1596] writeback: stabilize bdi->dirty_ratelimit There are some imperfections in balanced_dirty_ratelimit. 1) large fluctuations The dirty_rate used for computing balanced_dirty_ratelimit is merely averaged in the past 200ms (very small comparing to the 3s estimation period for write_bw), which makes rather dispersed distribution of balanced_dirty_ratelimit. It's pretty hard to average out the singular points by increasing the estimation period. Considering that the averaging technique will introduce very undesirable time lags, I give it up totally. (btw, the 3s write_bw averaging time lag is much more acceptable because its impact is one-way and therefore won't lead to oscillations.) The more practical way is filtering -- most singular balanced_dirty_ratelimit points can be filtered out by remembering some prev_balanced_rate and prev_prev_balanced_rate. However the more reliable way is to guard balanced_dirty_ratelimit with task_ratelimit. 2) due to truncates and fs redirties, the (write_bw <=> dirty_rate) match could become unbalanced, which may lead to large systematical errors in balanced_dirty_ratelimit. The truncates, due to its possibly bumpy nature, can hardly be compensated smoothly. So let's face it. When some over-estimated balanced_dirty_ratelimit brings dirty_ratelimit high, dirty pages will go higher than the setpoint. task_ratelimit will in turn become lower than dirty_ratelimit. So if we consider both balanced_dirty_ratelimit and task_ratelimit and update dirty_ratelimit only when they are on the same side of dirty_ratelimit, the systematical errors in balanced_dirty_ratelimit won't be able to bring dirty_ratelimit far away. The balanced_dirty_ratelimit estimation may also be inaccurate near @limit or @freerun, however is less an issue. 3) since we ultimately want to - keep the fluctuations of task ratelimit as small as possible - keep the dirty pages around the setpoint as long time as possible the update policy used for (2) also serves the above goals nicely: if for some reason the dirty pages are high (task_ratelimit < dirty_ratelimit), and dirty_ratelimit is low (dirty_ratelimit < balanced_dirty_ratelimit), there is no point to bring up dirty_ratelimit in a hurry only to hurt both the above two goals. So, we make use of task_ratelimit to limit the update of dirty_ratelimit in two ways: 1) avoid changing dirty rate when it's against the position control target (the adjusted rate will slow down the progress of dirty pages going back to setpoint). 2) limit the step size. task_ratelimit is changing values step by step, leaving a consistent trace comparing to the randomly jumping balanced_dirty_ratelimit. task_ratelimit also has the nice smaller errors in stable state and typically larger errors when there are big errors in rate. So it's a pretty good limiting factor for the step size of dirty_ratelimit. Note that bdi->dirty_ratelimit is always tracking balanced_dirty_ratelimit. task_ratelimit is merely used as a limiting factor. Signed-off-by: Wu Fengguang --- include/linux/backing-dev.h | 3 ++ mm/backing-dev.c | 1 + mm/page-writeback.c | 71 ++++++++++++++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index dff0ff78e878..c3b92010d894 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -83,8 +83,11 @@ struct backing_dev_info { /* * The base dirty throttle rate, re-calculated on every 200ms. * All the bdi tasks' dirty rate will be curbed under it. + * @dirty_ratelimit tracks the estimated @balanced_dirty_ratelimit + * in small steps and is much more smooth/stable than the latter. */ unsigned long dirty_ratelimit; + unsigned long balanced_dirty_ratelimit; struct prop_local_percpu completions; int dirty_exceeded; diff --git a/mm/backing-dev.c b/mm/backing-dev.c index ba20f94cde93..5dcaa3c756d1 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -686,6 +686,7 @@ int bdi_init(struct backing_dev_info *bdi) bdi->bw_time_stamp = jiffies; bdi->written_stamp = 0; + bdi->balanced_dirty_ratelimit = INIT_BW; bdi->dirty_ratelimit = INIT_BW; bdi->write_bandwidth = INIT_BW; bdi->avg_write_bandwidth = INIT_BW; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 1721b6523c04..d4a6e91bd9e5 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -792,12 +792,17 @@ static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi, unsigned long dirtied, unsigned long elapsed) { + unsigned long freerun = dirty_freerun_ceiling(thresh, bg_thresh); + unsigned long limit = hard_dirty_limit(thresh); + unsigned long setpoint = (freerun + limit) / 2; unsigned long write_bw = bdi->avg_write_bandwidth; unsigned long dirty_ratelimit = bdi->dirty_ratelimit; unsigned long dirty_rate; unsigned long task_ratelimit; unsigned long balanced_dirty_ratelimit; unsigned long pos_ratio; + unsigned long step; + unsigned long x; /* * The dirty rate will match the writeout rate in long term, except @@ -847,7 +852,71 @@ static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi, balanced_dirty_ratelimit = div_u64((u64)task_ratelimit * write_bw, dirty_rate | 1); - bdi->dirty_ratelimit = max(balanced_dirty_ratelimit, 1UL); + /* + * We could safely do this and return immediately: + * + * bdi->dirty_ratelimit = balanced_dirty_ratelimit; + * + * However to get a more stable dirty_ratelimit, the below elaborated + * code makes use of task_ratelimit to filter out sigular points and + * limit the step size. + * + * The below code essentially only uses the relative value of + * + * task_ratelimit - dirty_ratelimit + * = (pos_ratio - 1) * dirty_ratelimit + * + * which reflects the direction and size of dirty position error. + */ + + /* + * dirty_ratelimit will follow balanced_dirty_ratelimit iff + * task_ratelimit is on the same side of dirty_ratelimit, too. + * For example, when + * - dirty_ratelimit > balanced_dirty_ratelimit + * - dirty_ratelimit > task_ratelimit (dirty pages are above setpoint) + * lowering dirty_ratelimit will help meet both the position and rate + * control targets. Otherwise, don't update dirty_ratelimit if it will + * only help meet the rate target. After all, what the users ultimately + * feel and care are stable dirty rate and small position error. + * + * |task_ratelimit - dirty_ratelimit| is used to limit the step size + * and filter out the sigular points of balanced_dirty_ratelimit. Which + * keeps jumping around randomly and can even leap far away at times + * due to the small 200ms estimation period of dirty_rate (we want to + * keep that period small to reduce time lags). + */ + step = 0; + if (dirty < setpoint) { + x = min(bdi->balanced_dirty_ratelimit, + min(balanced_dirty_ratelimit, task_ratelimit)); + if (dirty_ratelimit < x) + step = x - dirty_ratelimit; + } else { + x = max(bdi->balanced_dirty_ratelimit, + max(balanced_dirty_ratelimit, task_ratelimit)); + if (dirty_ratelimit > x) + step = dirty_ratelimit - x; + } + + /* + * Don't pursue 100% rate matching. It's impossible since the balanced + * rate itself is constantly fluctuating. So decrease the track speed + * when it gets close to the target. Helps eliminate pointless tremors. + */ + step >>= dirty_ratelimit / (2 * step + 1); + /* + * Limit the tracking speed to avoid overshooting. + */ + step = (step + 7) / 8; + + if (dirty_ratelimit < balanced_dirty_ratelimit) + dirty_ratelimit += step; + else + dirty_ratelimit -= step; + + bdi->dirty_ratelimit = max(dirty_ratelimit, 1UL); + bdi->balanced_dirty_ratelimit = balanced_dirty_ratelimit; } void __bdi_update_bandwidth(struct backing_dev_info *bdi, From 9d823e8f6b1b7b39f952d7d1795f29162143a433 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 11 Jun 2011 18:10:12 -0600 Subject: [PATCH 0509/1596] writeback: per task dirty rate limit Add two fields to task_struct. 1) account dirtied pages in the individual tasks, for accuracy 2) per-task balance_dirty_pages() call intervals, for flexibility The balance_dirty_pages() call interval (ie. nr_dirtied_pause) will scale near-sqrt to the safety gap between dirty pages and threshold. The main problem of per-task nr_dirtied is, if 1k+ tasks start dirtying pages at exactly the same time, each task will be assigned a large initial nr_dirtied_pause, so that the dirty threshold will be exceeded long before each task reached its nr_dirtied_pause and hence call balance_dirty_pages(). The solution is to watch for the number of pages dirtied on each CPU in between the calls into balance_dirty_pages(). If it exceeds ratelimit_pages (3% dirty threshold), force call balance_dirty_pages() for a chance to set bdi->dirty_exceeded. In normal situations, this safeguarding condition is not expected to trigger at all. On the sqrt in dirty_poll_interval(): It will serve as an initial guess when dirty pages are still in the freerun area. When dirty pages are floating inside the dirty control scope [freerun, limit], a followup patch will use some refined dirty poll interval to get the desired pause time. thresh-dirty (MB) sqrt 1 16 2 22 4 32 8 45 16 64 32 90 64 128 128 181 256 256 512 362 1024 512 The above table means, given 1MB (or 1GB) gap and the dd tasks polling balance_dirty_pages() on every 16 (or 512) pages, the dirty limit won't be exceeded as long as there are less than 16 (or 512) concurrent dd's. So sqrt naturally leads to less overheads and more safe concurrent tasks for large memory servers, which have large (thresh-freerun) gaps. peter: keep the per-CPU ratelimit for safeguarding the 1k+ tasks case CC: Peter Zijlstra Reviewed-by: Andrea Righi Signed-off-by: Wu Fengguang --- include/linux/sched.h | 7 ++++ kernel/fork.c | 3 ++ mm/page-writeback.c | 89 ++++++++++++++++++++++++------------------- 3 files changed, 60 insertions(+), 39 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 41d0237fd449..a4a5582dc618 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1525,6 +1525,13 @@ struct task_struct { int make_it_fail; #endif struct prop_local_single dirties; + /* + * when (nr_dirtied >= nr_dirtied_pause), it's time to call + * balance_dirty_pages() for some dirty throttling pause + */ + int nr_dirtied; + int nr_dirtied_pause; + #ifdef CONFIG_LATENCYTOP int latency_record_count; struct latency_record latency_record[LT_SAVECOUNT]; diff --git a/kernel/fork.c b/kernel/fork.c index 8e6b6f4fb272..cc0815df99f2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1302,6 +1302,9 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->pdeath_signal = 0; p->exit_state = 0; + p->nr_dirtied = 0; + p->nr_dirtied_pause = 128 >> (PAGE_SHIFT - 10); + /* * Ok, make it visible to the rest of the system. * We dont wake it up yet. diff --git a/mm/page-writeback.c b/mm/page-writeback.c index d4a6e91bd9e5..daff320d263f 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -54,20 +54,6 @@ */ static long ratelimit_pages = 32; -/* - * When balance_dirty_pages decides that the caller needs to perform some - * non-background writeback, this is how many pages it will attempt to write. - * It should be somewhat larger than dirtied pages to ensure that reasonably - * large amounts of I/O are submitted. - */ -static inline long sync_writeback_pages(unsigned long dirtied) -{ - if (dirtied < ratelimit_pages) - dirtied = ratelimit_pages; - - return dirtied + dirtied / 2; -} - /* The following parameters are exported via /proc/sys/vm */ /* @@ -169,6 +155,8 @@ static void update_completion_period(void) int shift = calc_period_shift(); prop_change_shift(&vm_completions, shift); prop_change_shift(&vm_dirties, shift); + + writeback_set_ratelimit(); } int dirty_background_ratio_handler(struct ctl_table *table, int write, @@ -978,6 +966,23 @@ static void bdi_update_bandwidth(struct backing_dev_info *bdi, spin_unlock(&bdi->wb.list_lock); } +/* + * After a task dirtied this many pages, balance_dirty_pages_ratelimited_nr() + * will look to see if it needs to start dirty throttling. + * + * If dirty_poll_interval is too low, big NUMA machines will call the expensive + * global_page_state() too often. So scale it near-sqrt to the safety margin + * (the number of pages we may dirty without exceeding the dirty limits). + */ +static unsigned long dirty_poll_interval(unsigned long dirty, + unsigned long thresh) +{ + if (thresh > dirty) + return 1UL << (ilog2(thresh - dirty) >> 1); + + return 1; +} + /* * balance_dirty_pages() must be called by processes which are generating dirty * data. It looks at the number of dirty pages in the machine and will force @@ -1112,6 +1117,9 @@ static void balance_dirty_pages(struct address_space *mapping, if (clear_dirty_exceeded && bdi->dirty_exceeded) bdi->dirty_exceeded = 0; + current->nr_dirtied = 0; + current->nr_dirtied_pause = dirty_poll_interval(nr_dirty, dirty_thresh); + if (writeback_in_progress(bdi)) return; @@ -1138,7 +1146,7 @@ void set_page_dirty_balance(struct page *page, int page_mkwrite) } } -static DEFINE_PER_CPU(unsigned long, bdp_ratelimits) = 0; +static DEFINE_PER_CPU(int, bdp_ratelimits); /** * balance_dirty_pages_ratelimited_nr - balance dirty memory state @@ -1158,31 +1166,39 @@ void balance_dirty_pages_ratelimited_nr(struct address_space *mapping, unsigned long nr_pages_dirtied) { struct backing_dev_info *bdi = mapping->backing_dev_info; - unsigned long ratelimit; - unsigned long *p; + int ratelimit; + int *p; if (!bdi_cap_account_dirty(bdi)) return; - ratelimit = ratelimit_pages; - if (mapping->backing_dev_info->dirty_exceeded) - ratelimit = 8; + ratelimit = current->nr_dirtied_pause; + if (bdi->dirty_exceeded) + ratelimit = min(ratelimit, 32 >> (PAGE_SHIFT - 10)); + + current->nr_dirtied += nr_pages_dirtied; + preempt_disable(); /* - * Check the rate limiting. Also, we do not want to throttle real-time - * tasks in balance_dirty_pages(). Period. + * This prevents one CPU to accumulate too many dirtied pages without + * calling into balance_dirty_pages(), which can happen when there are + * 1000+ tasks, all of them start dirtying pages at exactly the same + * time, hence all honoured too large initial task->nr_dirtied_pause. */ - preempt_disable(); p = &__get_cpu_var(bdp_ratelimits); - *p += nr_pages_dirtied; - if (unlikely(*p >= ratelimit)) { - ratelimit = sync_writeback_pages(*p); + if (unlikely(current->nr_dirtied >= ratelimit)) *p = 0; - preempt_enable(); - balance_dirty_pages(mapping, ratelimit); - return; + else { + *p += nr_pages_dirtied; + if (unlikely(*p >= ratelimit_pages)) { + *p = 0; + ratelimit = 0; + } } preempt_enable(); + + if (unlikely(current->nr_dirtied >= ratelimit)) + balance_dirty_pages(mapping, current->nr_dirtied); } EXPORT_SYMBOL(balance_dirty_pages_ratelimited_nr); @@ -1277,22 +1293,17 @@ void laptop_sync_completion(void) * * Here we set ratelimit_pages to a level which ensures that when all CPUs are * dirtying in parallel, we cannot go more than 3% (1/32) over the dirty memory - * thresholds before writeback cuts in. - * - * But the limit should not be set too high. Because it also controls the - * amount of memory which the balance_dirty_pages() caller has to write back. - * If this is too large then the caller will block on the IO queue all the - * time. So limit it to four megabytes - the balance_dirty_pages() caller - * will write six megabyte chunks, max. + * thresholds. */ void writeback_set_ratelimit(void) { - ratelimit_pages = vm_total_pages / (num_online_cpus() * 32); + unsigned long background_thresh; + unsigned long dirty_thresh; + global_dirty_limits(&background_thresh, &dirty_thresh); + ratelimit_pages = dirty_thresh / (num_online_cpus() * 32); if (ratelimit_pages < 16) ratelimit_pages = 16; - if (ratelimit_pages * PAGE_CACHE_SIZE > 4096 * 1024) - ratelimit_pages = (4096 * 1024) / PAGE_CACHE_SIZE; } static int __cpuinit From 143dfe8611a63030ce0c79419dc362f7838be557 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 27 Aug 2010 18:45:12 -0600 Subject: [PATCH 0510/1596] writeback: IO-less balance_dirty_pages() As proposed by Chris, Dave and Jan, don't start foreground writeback IO inside balance_dirty_pages(). Instead, simply let it idle sleep for some time to throttle the dirtying task. In the mean while, kick off the per-bdi flusher thread to do background writeback IO. RATIONALS ========= - disk seeks on concurrent writeback of multiple inodes (Dave Chinner) If every thread doing writes and being throttled start foreground writeback, it leads to N IO submitters from at least N different inodes at the same time, end up with N different sets of IO being issued with potentially zero locality to each other, resulting in much lower elevator sort/merge efficiency and hence we seek the disk all over the place to service the different sets of IO. OTOH, if there is only one submission thread, it doesn't jump between inodes in the same way when congestion clears - it keeps writing to the same inode, resulting in large related chunks of sequential IOs being issued to the disk. This is more efficient than the above foreground writeback because the elevator works better and the disk seeks less. - lock contention and cache bouncing on concurrent IO submitters (Dave Chinner) With this patchset, the fs_mark benchmark on a 12-drive software RAID0 goes from CPU bound to IO bound, freeing "3-4 CPUs worth of spinlock contention". * "CPU usage has dropped by ~55%", "it certainly appears that most of the CPU time saving comes from the removal of contention on the inode_wb_list_lock" (IMHO at least 10% comes from the reduction of cacheline bouncing, because the new code is able to call much less frequently into balance_dirty_pages() and hence access the global page states) * the user space "App overhead" is reduced by 20%, by avoiding the cacheline pollution by the complex writeback code path * "for a ~5% throughput reduction", "the number of write IOs have dropped by ~25%", and the elapsed time reduced from 41:42.17 to 40:53.23. * On a simple test of 100 dd, it reduces the CPU %system time from 30% to 3%, and improves IO throughput from 38MB/s to 42MB/s. - IO size too small for fast arrays and too large for slow USB sticks The write_chunk used by current balance_dirty_pages() cannot be directly set to some large value (eg. 128MB) for better IO efficiency. Because it could lead to more than 1 second user perceivable stalls. Even the current 4MB write size may be too large for slow USB sticks. The fact that balance_dirty_pages() starts IO on itself couples the IO size to wait time, which makes it hard to do suitable IO size while keeping the wait time under control. Now it's possible to increase writeback chunk size proportional to the disk bandwidth. In a simple test of 50 dd's on XFS, 1-HDD, 3GB ram, the larger writeback size dramatically reduces the seek count to 1/10 (far beyond my expectation) and improves the write throughput by 24%. - long block time in balance_dirty_pages() hurts desktop responsiveness Many of us may have the experience: it often takes a couple of seconds or even long time to stop a heavy writing dd/cp/tar command with Ctrl-C or "kill -9". - IO pipeline broken by bumpy write() progress There are a broad class of "loop {read(buf); write(buf);}" applications whose read() pipeline will be under-utilized or even come to a stop if the write()s have long latencies _or_ don't progress in a constant rate. The current threshold based throttling inherently transfers the large low level IO completion fluctuations to bumpy application write()s, and further deteriorates with increasing number of dirtiers and/or bdi's. For example, when doing 50 dd's + 1 remote rsync to an XFS partition, the rsync progresses very bumpy in legacy kernel, and throughput is improved by 67% by this patchset. (plus the larger write chunk size, it will be 93% speedup). The new rate based throttling can support 1000+ dd's with excellent smoothness, low latency and low overheads. For the above reasons, it's much better to do IO-less and low latency pauses in balance_dirty_pages(). Jan Kara, Dave Chinner and me explored the scheme to let balance_dirty_pages() wait for enough writeback IO completions to safeguard the dirty limit. However it's found to have two problems: - in large NUMA systems, the per-cpu counters may have big accounting errors, leading to big throttle wait time and jitters. - NFS may kill large amount of unstable pages with one single COMMIT. Because NFS server serves COMMIT with expensive fsync() IOs, it is desirable to delay and reduce the number of COMMITs. So it's not likely to optimize away such kind of bursty IO completions, and the resulted large (and tiny) stall times in IO completion based throttling. So here is a pause time oriented approach, which tries to control the pause time in each balance_dirty_pages() invocations, by controlling the number of pages dirtied before calling balance_dirty_pages(), for smooth and efficient dirty throttling: - avoid useless (eg. zero pause time) balance_dirty_pages() calls - avoid too small pause time (less than 4ms, which burns CPU power) - avoid too large pause time (more than 200ms, which hurts responsiveness) - avoid big fluctuations of pause times It can control pause times at will. The default policy (in a followup patch) will be to do ~10ms pauses in 1-dd case, and increase to ~100ms in 1000-dd case. BEHAVIOR CHANGE =============== (1) dirty threshold Users will notice that the applications will get throttled once crossing the global (background + dirty)/2=15% threshold, and then balanced around 17.5%. Before patch, the behavior is to just throttle it at 20% dirtyable memory in 1-dd case. Since the task will be soft throttled earlier than before, it may be perceived by end users as performance "slow down" if his application happens to dirty more than 15% dirtyable memory. (2) smoothness/responsiveness Users will notice a more responsive system during heavy writeback. "killall dd" will take effect instantly. Signed-off-by: Wu Fengguang --- include/trace/events/writeback.h | 24 ----- mm/page-writeback.c | 161 +++++++++++-------------------- 2 files changed, 56 insertions(+), 129 deletions(-) diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index 5f172703eb4f..178c23508d3d 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -104,30 +104,6 @@ DEFINE_WRITEBACK_EVENT(writeback_bdi_register); DEFINE_WRITEBACK_EVENT(writeback_bdi_unregister); DEFINE_WRITEBACK_EVENT(writeback_thread_start); DEFINE_WRITEBACK_EVENT(writeback_thread_stop); -DEFINE_WRITEBACK_EVENT(balance_dirty_start); -DEFINE_WRITEBACK_EVENT(balance_dirty_wait); - -TRACE_EVENT(balance_dirty_written, - - TP_PROTO(struct backing_dev_info *bdi, int written), - - TP_ARGS(bdi, written), - - TP_STRUCT__entry( - __array(char, name, 32) - __field(int, written) - ), - - TP_fast_assign( - strncpy(__entry->name, dev_name(bdi->dev), 32); - __entry->written = written; - ), - - TP_printk("bdi %s written %d", - __entry->name, - __entry->written - ) -); DECLARE_EVENT_CLASS(wbc_class, TP_PROTO(struct writeback_control *wbc, struct backing_dev_info *bdi), diff --git a/mm/page-writeback.c b/mm/page-writeback.c index daff320d263f..f32f25092c66 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -250,50 +250,6 @@ static void bdi_writeout_fraction(struct backing_dev_info *bdi, numerator, denominator); } -static inline void task_dirties_fraction(struct task_struct *tsk, - long *numerator, long *denominator) -{ - prop_fraction_single(&vm_dirties, &tsk->dirties, - numerator, denominator); -} - -/* - * task_dirty_limit - scale down dirty throttling threshold for one task - * - * task specific dirty limit: - * - * dirty -= (dirty/8) * p_{t} - * - * To protect light/slow dirtying tasks from heavier/fast ones, we start - * throttling individual tasks before reaching the bdi dirty limit. - * Relatively low thresholds will be allocated to heavy dirtiers. So when - * dirty pages grow large, heavy dirtiers will be throttled first, which will - * effectively curb the growth of dirty pages. Light dirtiers with high enough - * dirty threshold may never get throttled. - */ -#define TASK_LIMIT_FRACTION 8 -static unsigned long task_dirty_limit(struct task_struct *tsk, - unsigned long bdi_dirty) -{ - long numerator, denominator; - unsigned long dirty = bdi_dirty; - u64 inv = dirty / TASK_LIMIT_FRACTION; - - task_dirties_fraction(tsk, &numerator, &denominator); - inv *= numerator; - do_div(inv, denominator); - - dirty -= inv; - - return max(dirty, bdi_dirty/2); -} - -/* Minimum limit for any task */ -static unsigned long task_min_dirty_limit(unsigned long bdi_dirty) -{ - return bdi_dirty - bdi_dirty / TASK_LIMIT_FRACTION; -} - /* * */ @@ -986,30 +942,36 @@ static unsigned long dirty_poll_interval(unsigned long dirty, /* * balance_dirty_pages() must be called by processes which are generating dirty * data. It looks at the number of dirty pages in the machine and will force - * the caller to perform writeback if the system is over `vm_dirty_ratio'. + * the caller to wait once crossing the (background_thresh + dirty_thresh) / 2. * If we're over `background_thresh' then the writeback threads are woken to * perform some writeout. */ static void balance_dirty_pages(struct address_space *mapping, - unsigned long write_chunk) + unsigned long pages_dirtied) { - unsigned long nr_reclaimable, bdi_nr_reclaimable; + unsigned long nr_reclaimable; /* = file_dirty + unstable_nfs */ + unsigned long bdi_reclaimable; unsigned long nr_dirty; /* = file_dirty + writeback + unstable_nfs */ unsigned long bdi_dirty; unsigned long freerun; unsigned long background_thresh; unsigned long dirty_thresh; unsigned long bdi_thresh; - unsigned long task_bdi_thresh; - unsigned long min_task_bdi_thresh; - unsigned long pages_written = 0; - unsigned long pause = 1; + long pause = 0; bool dirty_exceeded = false; - bool clear_dirty_exceeded = true; + unsigned long task_ratelimit; + unsigned long dirty_ratelimit; + unsigned long pos_ratio; struct backing_dev_info *bdi = mapping->backing_dev_info; unsigned long start_time = jiffies; for (;;) { + /* + * Unstable writes are a feature of certain networked + * filesystems (i.e. NFS) in which data may have been + * written to the server's write cache, but has not yet + * been flushed to permanent storage. + */ nr_reclaimable = global_page_state(NR_FILE_DIRTY) + global_page_state(NR_UNSTABLE_NFS); nr_dirty = nr_reclaimable + global_page_state(NR_WRITEBACK); @@ -1026,9 +988,23 @@ static void balance_dirty_pages(struct address_space *mapping, if (nr_dirty <= freerun) break; + if (unlikely(!writeback_in_progress(bdi))) + bdi_start_background_writeback(bdi); + + /* + * bdi_thresh is not treated as some limiting factor as + * dirty_thresh, due to reasons + * - in JBOD setup, bdi_thresh can fluctuate a lot + * - in a system with HDD and USB key, the USB key may somehow + * go into state (bdi_dirty >> bdi_thresh) either because + * bdi_dirty starts high, or because bdi_thresh drops low. + * In this case we don't want to hard throttle the USB key + * dirtiers for 100 seconds until bdi_dirty drops under + * bdi_thresh. Instead the auxiliary bdi control line in + * bdi_position_ratio() will let the dirtier task progress + * at some rate <= (write_bw / 2) for bringing down bdi_dirty. + */ bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh); - min_task_bdi_thresh = task_min_dirty_limit(bdi_thresh); - task_bdi_thresh = task_dirty_limit(current, bdi_thresh); /* * In order to avoid the stacked BDI deadlock we need @@ -1040,57 +1016,41 @@ static void balance_dirty_pages(struct address_space *mapping, * actually dirty; with m+n sitting in the percpu * deltas. */ - if (task_bdi_thresh < 2 * bdi_stat_error(bdi)) { - bdi_nr_reclaimable = bdi_stat_sum(bdi, BDI_RECLAIMABLE); - bdi_dirty = bdi_nr_reclaimable + + if (bdi_thresh < 2 * bdi_stat_error(bdi)) { + bdi_reclaimable = bdi_stat_sum(bdi, BDI_RECLAIMABLE); + bdi_dirty = bdi_reclaimable + bdi_stat_sum(bdi, BDI_WRITEBACK); } else { - bdi_nr_reclaimable = bdi_stat(bdi, BDI_RECLAIMABLE); - bdi_dirty = bdi_nr_reclaimable + + bdi_reclaimable = bdi_stat(bdi, BDI_RECLAIMABLE); + bdi_dirty = bdi_reclaimable + bdi_stat(bdi, BDI_WRITEBACK); } - /* - * The bdi thresh is somehow "soft" limit derived from the - * global "hard" limit. The former helps to prevent heavy IO - * bdi or process from holding back light ones; The latter is - * the last resort safeguard. - */ - dirty_exceeded = (bdi_dirty > task_bdi_thresh) || + dirty_exceeded = (bdi_dirty > bdi_thresh) || (nr_dirty > dirty_thresh); - clear_dirty_exceeded = (bdi_dirty <= min_task_bdi_thresh) && - (nr_dirty <= dirty_thresh); - - if (!dirty_exceeded) - break; - - if (!bdi->dirty_exceeded) + if (dirty_exceeded && !bdi->dirty_exceeded) bdi->dirty_exceeded = 1; bdi_update_bandwidth(bdi, dirty_thresh, background_thresh, nr_dirty, bdi_thresh, bdi_dirty, start_time); - /* Note: nr_reclaimable denotes nr_dirty + nr_unstable. - * Unstable writes are a feature of certain networked - * filesystems (i.e. NFS) in which data may have been - * written to the server's write cache, but has not yet - * been flushed to permanent storage. - * Only move pages to writeback if this bdi is over its - * threshold otherwise wait until the disk writes catch - * up. - */ - trace_balance_dirty_start(bdi); - if (bdi_nr_reclaimable > task_bdi_thresh) { - pages_written += writeback_inodes_wb(&bdi->wb, - write_chunk); - trace_balance_dirty_written(bdi, pages_written); - if (pages_written >= write_chunk) - break; /* We've done our duty */ + dirty_ratelimit = bdi->dirty_ratelimit; + pos_ratio = bdi_position_ratio(bdi, dirty_thresh, + background_thresh, nr_dirty, + bdi_thresh, bdi_dirty); + if (unlikely(pos_ratio == 0)) { + pause = MAX_PAUSE; + goto pause; } + task_ratelimit = (u64)dirty_ratelimit * + pos_ratio >> RATELIMIT_CALC_SHIFT; + pause = (HZ * pages_dirtied) / (task_ratelimit | 1); + pause = min_t(long, pause, MAX_PAUSE); + +pause: __set_current_state(TASK_UNINTERRUPTIBLE); io_schedule_timeout(pause); - trace_balance_dirty_wait(bdi); dirty_thresh = hard_dirty_limit(dirty_thresh); /* @@ -1099,22 +1059,11 @@ static void balance_dirty_pages(struct address_space *mapping, * 200ms is typically more than enough to curb heavy dirtiers; * (b) the pause time limit makes the dirtiers more responsive. */ - if (nr_dirty < dirty_thresh && - bdi_dirty < (task_bdi_thresh + bdi_thresh) / 2 && - time_after(jiffies, start_time + MAX_PAUSE)) + if (nr_dirty < dirty_thresh) break; - - /* - * Increase the delay for each loop, up to our previous - * default of taking a 100ms nap. - */ - pause <<= 1; - if (pause > HZ / 10) - pause = HZ / 10; } - /* Clear dirty_exceeded flag only when no task can exceed the limit */ - if (clear_dirty_exceeded && bdi->dirty_exceeded) + if (!dirty_exceeded && bdi->dirty_exceeded) bdi->dirty_exceeded = 0; current->nr_dirtied = 0; @@ -1131,8 +1080,10 @@ static void balance_dirty_pages(struct address_space *mapping, * In normal mode, we start background writeout at the lower * background_thresh, to keep the amount of dirty memory low. */ - if ((laptop_mode && pages_written) || - (!laptop_mode && (nr_reclaimable > background_thresh))) + if (laptop_mode) + return; + + if (nr_reclaimable > background_thresh) bdi_start_background_writeback(bdi); } From c8462cc9de9e92264ec647903772f6036a99b286 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 11 Jun 2011 19:21:43 -0600 Subject: [PATCH 0511/1596] writeback: limit max dirty pause time Apply two policies to scale down the max pause time for 1) small number of concurrent dirtiers 2) small memory system (comparing to storage bandwidth) MAX_PAUSE=200ms may only be suitable for high end servers with lots of concurrent dirtiers, where the large pause time can reduce much overheads. Otherwise, smaller pause time is desirable whenever possible, so as to get good responsiveness and smooth user experiences. It's actually required for good disk utilization in the case when all the dirty pages can be synced to disk within MAX_PAUSE=200ms. Signed-off-by: Wu Fengguang --- mm/page-writeback.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index f32f25092c66..cc351e6f9ed9 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -939,6 +939,43 @@ static unsigned long dirty_poll_interval(unsigned long dirty, return 1; } +static unsigned long bdi_max_pause(struct backing_dev_info *bdi, + unsigned long bdi_dirty) +{ + unsigned long bw = bdi->avg_write_bandwidth; + unsigned long hi = ilog2(bw); + unsigned long lo = ilog2(bdi->dirty_ratelimit); + unsigned long t; + + /* target for 20ms max pause on 1-dd case */ + t = HZ / 50; + + /* + * Scale up pause time for concurrent dirtiers in order to reduce CPU + * overheads. + * + * (N * 20ms) on 2^N concurrent tasks. + */ + if (hi > lo) + t += (hi - lo) * (20 * HZ) / 1024; + + /* + * Limit pause time for small memory systems. If sleeping for too long + * time, a small pool of dirty/writeback pages may go empty and disk go + * idle. + * + * 8 serves as the safety ratio. + */ + if (bdi_dirty) + t = min(t, bdi_dirty * HZ / (8 * bw + 1)); + + /* + * The pause time will be settled within range (max_pause/4, max_pause). + * Apply a minimal value of 4 to get a non-zero max_pause/4. + */ + return clamp_val(t, 4, MAX_PAUSE); +} + /* * balance_dirty_pages() must be called by processes which are generating dirty * data. It looks at the number of dirty pages in the machine and will force @@ -958,6 +995,7 @@ static void balance_dirty_pages(struct address_space *mapping, unsigned long dirty_thresh; unsigned long bdi_thresh; long pause = 0; + long max_pause; bool dirty_exceeded = false; unsigned long task_ratelimit; unsigned long dirty_ratelimit; @@ -1035,18 +1073,20 @@ static void balance_dirty_pages(struct address_space *mapping, nr_dirty, bdi_thresh, bdi_dirty, start_time); + max_pause = bdi_max_pause(bdi, bdi_dirty); + dirty_ratelimit = bdi->dirty_ratelimit; pos_ratio = bdi_position_ratio(bdi, dirty_thresh, background_thresh, nr_dirty, bdi_thresh, bdi_dirty); if (unlikely(pos_ratio == 0)) { - pause = MAX_PAUSE; + pause = max_pause; goto pause; } task_ratelimit = (u64)dirty_ratelimit * pos_ratio >> RATELIMIT_CALC_SHIFT; pause = (HZ * pages_dirtied) / (task_ratelimit | 1); - pause = min_t(long, pause, MAX_PAUSE); + pause = min(pause, max_pause); pause: __set_current_state(TASK_UNINTERRUPTIBLE); From 57fc978cfb61ed40a7bbfe5a569359159ba31abd Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 11 Jun 2011 19:32:32 -0600 Subject: [PATCH 0512/1596] writeback: control dirty pause time The dirty pause time shall ultimately be controlled by adjusting nr_dirtied_pause, since there is relationship pause = pages_dirtied / task_ratelimit Assuming pages_dirtied ~= nr_dirtied_pause task_ratelimit ~= dirty_ratelimit We get nr_dirtied_pause ~= dirty_ratelimit * desired_pause Here dirty_ratelimit is preferred over task_ratelimit because it's more stable. It's also important to limit possible large transitional errors: - bw is changing quickly - pages_dirtied << nr_dirtied_pause on entering dirty exceeded area - pages_dirtied >> nr_dirtied_pause on btrfs (to be improved by a separate fix, but still expect non-trivial errors) So we end up using the above formula inside clamp_val(). The best test case for this code is to run 100 "dd bs=4M" tasks on btrfs and check its pause time distribution. Signed-off-by: Wu Fengguang --- mm/page-writeback.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index cc351e6f9ed9..6a8bb693b429 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1086,6 +1086,10 @@ static void balance_dirty_pages(struct address_space *mapping, task_ratelimit = (u64)dirty_ratelimit * pos_ratio >> RATELIMIT_CALC_SHIFT; pause = (HZ * pages_dirtied) / (task_ratelimit | 1); + if (unlikely(pause <= 0)) { + pause = 1; /* avoid resetting nr_dirtied_pause below */ + break; + } pause = min(pause, max_pause); pause: @@ -1107,7 +1111,21 @@ static void balance_dirty_pages(struct address_space *mapping, bdi->dirty_exceeded = 0; current->nr_dirtied = 0; - current->nr_dirtied_pause = dirty_poll_interval(nr_dirty, dirty_thresh); + if (pause == 0) { /* in freerun area */ + current->nr_dirtied_pause = + dirty_poll_interval(nr_dirty, dirty_thresh); + } else if (pause <= max_pause / 4 && + pages_dirtied >= current->nr_dirtied_pause) { + current->nr_dirtied_pause = clamp_val( + dirty_ratelimit * (max_pause / 2) / HZ, + pages_dirtied + pages_dirtied / 8, + pages_dirtied * 4); + } else if (pause >= max_pause) { + current->nr_dirtied_pause = 1 | clamp_val( + dirty_ratelimit * (max_pause / 2) / HZ, + pages_dirtied / 4, + pages_dirtied - pages_dirtied / 8); + } if (writeback_in_progress(bdi)) return; From 8927f66c4ede9a18b4b58f7e6f9debca67065f6b Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 4 Aug 2011 22:16:46 -0600 Subject: [PATCH 0513/1596] writeback: dirty position control - bdi reserve area Keep a minimal pool of dirty pages for each bdi, so that the disk IO queues won't underrun. Also gently increase a small bdi_thresh to avoid it stuck in 0 for some light dirtied bdi. It's particularly useful for JBOD and small memory system. It may result in (pos_ratio > 1) at the setpoint and push the dirty pages high. This is more or less intended because the bdi is in the danger of IO queue underflow. Signed-off-by: Wu Fengguang --- mm/page-writeback.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 6a8bb693b429..325f753c80ed 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -599,6 +599,7 @@ static unsigned long bdi_position_ratio(struct backing_dev_info *bdi, */ if (unlikely(bdi_thresh > thresh)) bdi_thresh = thresh; + bdi_thresh = max(bdi_thresh, (limit - dirty) / 8); /* * scale global setpoint to bdi's: * bdi_setpoint = setpoint * bdi_thresh / thresh @@ -622,6 +623,20 @@ static unsigned long bdi_position_ratio(struct backing_dev_info *bdi, } else pos_ratio /= 4; + /* + * bdi reserve area, safeguard against dirty pool underrun and disk idle + * It may push the desired control point of global dirty pages higher + * than setpoint. + */ + x_intercept = bdi_thresh / 2; + if (bdi_dirty < x_intercept) { + if (bdi_dirty > x_intercept / 8) { + pos_ratio *= x_intercept; + do_div(pos_ratio, bdi_dirty); + } else + pos_ratio *= 8; + } + return pos_ratio; } From b00949aa2df9970a912bf060bc95e99da356881c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 18 Nov 2010 14:38:33 -0600 Subject: [PATCH 0514/1596] writeback: per-bdi background threshold One thing puzzled me is that in JBOD case, the per-disk writeout performance is smaller than the corresponding single-disk case even when they have comparable bdi_thresh. Tracing shows find that in single disk case, bdi_writeback is always kept high while in JBOD case, it could drop low from time to time and correspondingly bdi_reclaimable could sometimes rush high. The fix is to watch bdi_reclaimable and kick background writeback as soon as it goes high. This resembles the global background threshold but in per-bdi manner. The trick is, as long as bdi_reclaimable does not go high, bdi_writeback naturally won't go low because bdi_reclaimable+bdi_writeback ~= bdi_thresh. With less fluctuated writeback pages, JBOD performance is observed to increase noticeably in various cases. vmstat:nr_written values before/after patch: 3.1.0-rc4-wo-underrun+ 3.1.0-rc4-bgthresh3+ ------------------------ ------------------------ 125596480 +25.9% 158179363 JBOD-10HDD-16G/ext4-100dd-1M-24p-16384M-20:10-X 61790815 +110.4% 130032231 JBOD-10HDD-16G/ext4-10dd-1M-24p-16384M-20:10-X 58853546 -0.1% 58823828 JBOD-10HDD-16G/ext4-1dd-1M-24p-16384M-20:10-X 110159811 +24.7% 137355377 JBOD-10HDD-16G/xfs-100dd-1M-24p-16384M-20:10-X 69544762 +10.8% 77080047 JBOD-10HDD-16G/xfs-10dd-1M-24p-16384M-20:10-X 50644862 +0.5% 50890006 JBOD-10HDD-16G/xfs-1dd-1M-24p-16384M-20:10-X 42677090 +28.0% 54643527 JBOD-10HDD-thresh=100M/ext4-100dd-1M-24p-16384M-100M:10-X 47491324 +13.3% 53785605 JBOD-10HDD-thresh=100M/ext4-10dd-1M-24p-16384M-100M:10-X 52548986 +0.9% 53001031 JBOD-10HDD-thresh=100M/ext4-1dd-1M-24p-16384M-100M:10-X 26783091 +36.8% 36650248 JBOD-10HDD-thresh=100M/xfs-100dd-1M-24p-16384M-100M:10-X 35526347 +14.0% 40492312 JBOD-10HDD-thresh=100M/xfs-10dd-1M-24p-16384M-100M:10-X 44670723 -1.1% 44177606 JBOD-10HDD-thresh=100M/xfs-1dd-1M-24p-16384M-100M:10-X 127996037 +22.4% 156719990 JBOD-10HDD-thresh=2G/ext4-100dd-1M-24p-16384M-2048M:10-X 57518856 +3.8% 59677625 JBOD-10HDD-thresh=2G/ext4-10dd-1M-24p-16384M-2048M:10-X 51919909 +12.2% 58269894 JBOD-10HDD-thresh=2G/ext4-1dd-1M-24p-16384M-2048M:10-X 86410514 +79.0% 154660433 JBOD-10HDD-thresh=2G/xfs-100dd-1M-24p-16384M-2048M:10-X 40132519 +38.6% 55617893 JBOD-10HDD-thresh=2G/xfs-10dd-1M-24p-16384M-2048M:10-X 48423248 +7.5% 52042927 JBOD-10HDD-thresh=2G/xfs-1dd-1M-24p-16384M-2048M:10-X 206041046 +44.1% 296846536 JBOD-10HDD-thresh=4G/xfs-100dd-1M-24p-16384M-4096M:10-X 72312903 -19.4% 58272885 JBOD-10HDD-thresh=4G/xfs-10dd-1M-24p-16384M-4096M:10-X 50635672 -0.5% 50384787 JBOD-10HDD-thresh=4G/xfs-1dd-1M-24p-16384M-4096M:10-X 68308534 +115.7% 147324758 JBOD-10HDD-thresh=800M/ext4-100dd-1M-24p-16384M-800M:10-X 57882933 +14.5% 66269621 JBOD-10HDD-thresh=800M/ext4-10dd-1M-24p-16384M-800M:10-X 52183472 +12.8% 58855181 JBOD-10HDD-thresh=800M/ext4-1dd-1M-24p-16384M-800M:10-X 53788956 +94.2% 104460352 JBOD-10HDD-thresh=800M/xfs-100dd-1M-24p-16384M-800M:10-X 44493342 +35.5% 60298210 JBOD-10HDD-thresh=800M/xfs-10dd-1M-24p-16384M-800M:10-X 42641209 +18.9% 50681038 JBOD-10HDD-thresh=800M/xfs-1dd-1M-24p-16384M-800M:10-X Signed-off-by: Wu Fengguang --- fs/fs-writeback.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 28076562ada0..6401cd76f109 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -658,14 +658,21 @@ long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages) return nr_pages - work.nr_pages; } -static inline bool over_bground_thresh(void) +static bool over_bground_thresh(struct backing_dev_info *bdi) { unsigned long background_thresh, dirty_thresh; global_dirty_limits(&background_thresh, &dirty_thresh); - return (global_page_state(NR_FILE_DIRTY) + - global_page_state(NR_UNSTABLE_NFS) > background_thresh); + if (global_page_state(NR_FILE_DIRTY) + + global_page_state(NR_UNSTABLE_NFS) > background_thresh) + return true; + + if (bdi_stat(bdi, BDI_RECLAIMABLE) > + bdi_dirty_limit(bdi, background_thresh)) + return true; + + return false; } /* @@ -727,7 +734,7 @@ static long wb_writeback(struct bdi_writeback *wb, * For background writeout, stop when we are below the * background dirty threshold */ - if (work->for_background && !over_bground_thresh()) + if (work->for_background && !over_bground_thresh(wb->bdi)) break; if (work->for_kupdate) { @@ -811,7 +818,7 @@ static unsigned long get_nr_dirty_pages(void) static long wb_check_background_flush(struct bdi_writeback *wb) { - if (over_bground_thresh()) { + if (over_bground_thresh(wb->bdi)) { struct wb_writeback_work work = { .nr_pages = LONG_MAX, From 6e01280f34be02e5e7635debb045aab3705bb5bf Mon Sep 17 00:00:00 2001 From: Inderpal Singh Date: Mon, 3 Oct 2011 08:51:20 +0900 Subject: [PATCH 0515/1596] ARM: EXYNOS4: Configure MAX8997 PMIC for ORIGEN Configure MAX8997 PMIC and provide platform specific data for ORIGEN board. Signed-off-by: Inderpal Singh Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/mach-origen.c | 396 +++++++++++++++++++++++++++- 1 file changed, 392 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index c8121fcf198d..3da77766961e 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include #include @@ -78,6 +81,378 @@ static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { }, }; +static struct regulator_consumer_supply __initdata ldo3_consumer[] = { + REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */ +}; +static struct regulator_consumer_supply __initdata ldo6_consumer[] = { + REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), /* MIPI */ +}; +static struct regulator_consumer_supply __initdata ldo7_consumer[] = { + REGULATOR_SUPPLY("avdd", "alc5625"), /* Realtek ALC5625 */ +}; +static struct regulator_consumer_supply __initdata ldo8_consumer[] = { + REGULATOR_SUPPLY("vdd", "s5p-adc"), /* ADC */ +}; +static struct regulator_consumer_supply __initdata ldo9_consumer[] = { + REGULATOR_SUPPLY("dvdd", "swb-a31"), /* AR6003 WLAN & CSR 8810 BT */ +}; +static struct regulator_consumer_supply __initdata ldo11_consumer[] = { + REGULATOR_SUPPLY("dvdd", "alc5625"), /* Realtek ALC5625 */ +}; +static struct regulator_consumer_supply __initdata ldo14_consumer[] = { + REGULATOR_SUPPLY("avdd18", "swb-a31"), /* AR6003 WLAN & CSR 8810 BT */ +}; +static struct regulator_consumer_supply __initdata ldo17_consumer[] = { + REGULATOR_SUPPLY("vdd33", "swb-a31"), /* AR6003 WLAN & CSR 8810 BT */ +}; +static struct regulator_consumer_supply __initdata buck1_consumer[] = { + REGULATOR_SUPPLY("vdd_arm", NULL), /* CPUFREQ */ +}; +static struct regulator_consumer_supply __initdata buck2_consumer[] = { + REGULATOR_SUPPLY("vdd_int", NULL), /* CPUFREQ */ +}; +static struct regulator_consumer_supply __initdata buck3_consumer[] = { + REGULATOR_SUPPLY("vdd_g3d", "mali_drm"), /* G3D */ +}; +static struct regulator_consumer_supply __initdata buck7_consumer[] = { + REGULATOR_SUPPLY("vcc", "platform-lcd"), /* LCD */ +}; + +static struct regulator_init_data __initdata max8997_ldo1_data = { + .constraints = { + .name = "VDD_ABB_3.3V", + .min_uV = 3300000, + .max_uV = 3300000, + .apply_uV = 1, + .state_mem = { + .disabled = 1, + }, + }, +}; + +static struct regulator_init_data __initdata max8997_ldo2_data = { + .constraints = { + .name = "VDD_ALIVE_1.1V", + .min_uV = 1100000, + .max_uV = 1100000, + .apply_uV = 1, + .always_on = 1, + .state_mem = { + .enabled = 1, + }, + }, +}; + +static struct regulator_init_data __initdata max8997_ldo3_data = { + .constraints = { + .name = "VMIPI_1.1V", + .min_uV = 1100000, + .max_uV = 1100000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo3_consumer), + .consumer_supplies = ldo3_consumer, +}; + +static struct regulator_init_data __initdata max8997_ldo4_data = { + .constraints = { + .name = "VDD_RTC_1.8V", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = 1, + .always_on = 1, + .state_mem = { + .disabled = 1, + }, + }, +}; + +static struct regulator_init_data __initdata max8997_ldo6_data = { + .constraints = { + .name = "VMIPI_1.8V", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo6_consumer), + .consumer_supplies = ldo6_consumer, +}; + +static struct regulator_init_data __initdata max8997_ldo7_data = { + .constraints = { + .name = "VDD_AUD_1.8V", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo7_consumer), + .consumer_supplies = ldo7_consumer, +}; + +static struct regulator_init_data __initdata max8997_ldo8_data = { + .constraints = { + .name = "VADC_3.3V", + .min_uV = 3300000, + .max_uV = 3300000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo8_consumer), + .consumer_supplies = ldo8_consumer, +}; + +static struct regulator_init_data __initdata max8997_ldo9_data = { + .constraints = { + .name = "DVDD_SWB_2.8V", + .min_uV = 2800000, + .max_uV = 2800000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo9_consumer), + .consumer_supplies = ldo9_consumer, +}; + +static struct regulator_init_data __initdata max8997_ldo10_data = { + .constraints = { + .name = "VDD_PLL_1.1V", + .min_uV = 1100000, + .max_uV = 1100000, + .apply_uV = 1, + .always_on = 1, + .state_mem = { + .disabled = 1, + }, + }, +}; + +static struct regulator_init_data __initdata max8997_ldo11_data = { + .constraints = { + .name = "VDD_AUD_3V", + .min_uV = 3000000, + .max_uV = 3000000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo11_consumer), + .consumer_supplies = ldo11_consumer, +}; + +static struct regulator_init_data __initdata max8997_ldo14_data = { + .constraints = { + .name = "AVDD18_SWB_1.8V", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo14_consumer), + .consumer_supplies = ldo14_consumer, +}; + +static struct regulator_init_data __initdata max8997_ldo17_data = { + .constraints = { + .name = "VDD_SWB_3.3V", + .min_uV = 3300000, + .max_uV = 3300000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo17_consumer), + .consumer_supplies = ldo17_consumer, +}; + +static struct regulator_init_data __initdata max8997_ldo21_data = { + .constraints = { + .name = "VDD_MIF_1.2V", + .min_uV = 1200000, + .max_uV = 1200000, + .apply_uV = 1, + .always_on = 1, + .state_mem = { + .disabled = 1, + }, + }, +}; + +static struct regulator_init_data __initdata max8997_buck1_data = { + .constraints = { + .name = "VDD_ARM_1.2V", + .min_uV = 950000, + .max_uV = 1350000, + .always_on = 1, + .boot_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(buck1_consumer), + .consumer_supplies = buck1_consumer, +}; + +static struct regulator_init_data __initdata max8997_buck2_data = { + .constraints = { + .name = "VDD_INT_1.1V", + .min_uV = 900000, + .max_uV = 1100000, + .always_on = 1, + .boot_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(buck2_consumer), + .consumer_supplies = buck2_consumer, +}; + +static struct regulator_init_data __initdata max8997_buck3_data = { + .constraints = { + .name = "VDD_G3D_1.1V", + .min_uV = 900000, + .max_uV = 1100000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(buck3_consumer), + .consumer_supplies = buck3_consumer, +}; + +static struct regulator_init_data __initdata max8997_buck5_data = { + .constraints = { + .name = "VDDQ_M1M2_1.2V", + .min_uV = 1200000, + .max_uV = 1200000, + .apply_uV = 1, + .always_on = 1, + .state_mem = { + .disabled = 1, + }, + }, +}; + +static struct regulator_init_data __initdata max8997_buck7_data = { + .constraints = { + .name = "VDD_LCD_3.3V", + .min_uV = 3300000, + .max_uV = 3300000, + .boot_on = 1, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .state_mem = { + .disabled = 1 + }, + }, + .num_consumer_supplies = ARRAY_SIZE(buck7_consumer), + .consumer_supplies = buck7_consumer, +}; + +static struct max8997_regulator_data __initdata origen_max8997_regulators[] = { + { MAX8997_LDO1, &max8997_ldo1_data }, + { MAX8997_LDO2, &max8997_ldo2_data }, + { MAX8997_LDO3, &max8997_ldo3_data }, + { MAX8997_LDO4, &max8997_ldo4_data }, + { MAX8997_LDO6, &max8997_ldo6_data }, + { MAX8997_LDO7, &max8997_ldo7_data }, + { MAX8997_LDO8, &max8997_ldo8_data }, + { MAX8997_LDO9, &max8997_ldo9_data }, + { MAX8997_LDO10, &max8997_ldo10_data }, + { MAX8997_LDO11, &max8997_ldo11_data }, + { MAX8997_LDO14, &max8997_ldo14_data }, + { MAX8997_LDO17, &max8997_ldo17_data }, + { MAX8997_LDO21, &max8997_ldo21_data }, + { MAX8997_BUCK1, &max8997_buck1_data }, + { MAX8997_BUCK2, &max8997_buck2_data }, + { MAX8997_BUCK3, &max8997_buck3_data }, + { MAX8997_BUCK5, &max8997_buck5_data }, + { MAX8997_BUCK7, &max8997_buck7_data }, +}; + +struct max8997_platform_data __initdata origen_max8997_pdata = { + .num_regulators = ARRAY_SIZE(origen_max8997_regulators), + .regulators = origen_max8997_regulators, + + .wakeup = true, + .buck1_gpiodvs = false, + .buck2_gpiodvs = false, + .buck5_gpiodvs = false, + .irq_base = IRQ_GPIO_END + 1, + + .ignore_gpiodvs_side_effect = true, + .buck125_default_idx = 0x0, + + .buck125_gpios[0] = EXYNOS4_GPX0(0), + .buck125_gpios[1] = EXYNOS4_GPX0(1), + .buck125_gpios[2] = EXYNOS4_GPX0(2), + + .buck1_voltage[0] = 1350000, + .buck1_voltage[1] = 1300000, + .buck1_voltage[2] = 1250000, + .buck1_voltage[3] = 1200000, + .buck1_voltage[4] = 1150000, + .buck1_voltage[5] = 1100000, + .buck1_voltage[6] = 1000000, + .buck1_voltage[7] = 950000, + + .buck2_voltage[0] = 1100000, + .buck2_voltage[1] = 1100000, + .buck2_voltage[2] = 1100000, + .buck2_voltage[3] = 1100000, + .buck2_voltage[4] = 1000000, + .buck2_voltage[5] = 1000000, + .buck2_voltage[6] = 1000000, + .buck2_voltage[7] = 1000000, + + .buck5_voltage[0] = 1200000, + .buck5_voltage[1] = 1200000, + .buck5_voltage[2] = 1200000, + .buck5_voltage[3] = 1200000, + .buck5_voltage[4] = 1200000, + .buck5_voltage[5] = 1200000, + .buck5_voltage[6] = 1200000, + .buck5_voltage[7] = 1200000, +}; + +/* I2C0 */ +static struct i2c_board_info i2c0_devs[] __initdata = { + { + I2C_BOARD_INFO("max8997", (0xCC >> 1)), + .platform_data = &origen_max8997_pdata, + .irq = IRQ_EINT(4), + }, +}; + static struct s3c_sdhci_platdata origen_hsmmc0_pdata __initdata = { .cd_type = S3C_SDHCI_CD_INTERNAL, .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, @@ -155,6 +530,7 @@ static struct platform_device origen_device_gpiokeys = { }; static struct platform_device *origen_devices[] __initdata = { + &s3c_device_i2c0, &s3c_device_hsmmc2, &s3c_device_hsmmc0, &s3c_device_rtc, @@ -172,13 +548,13 @@ static struct platform_device *origen_devices[] __initdata = { /* LCD Backlight data */ static struct samsung_bl_gpio_info origen_bl_gpio_info = { - .no = EXYNOS4_GPD0(0), - .func = S3C_GPIO_SFN(2), + .no = EXYNOS4_GPD0(0), + .func = S3C_GPIO_SFN(2), }; static struct platform_pwm_backlight_data origen_bl_data = { - .pwm_id = 0, - .pwm_period_ns = 1000, + .pwm_id = 0, + .pwm_period_ns = 1000, }; static void __init origen_map_io(void) @@ -188,8 +564,20 @@ static void __init origen_map_io(void) s3c24xx_init_uarts(origen_uartcfgs, ARRAY_SIZE(origen_uartcfgs)); } +static void __init origen_power_init(void) +{ + gpio_request(EXYNOS4_GPX0(4), "PMIC_IRQ"); + s3c_gpio_cfgpin(EXYNOS4_GPX0(4), S3C_GPIO_SFN(0xf)); + s3c_gpio_setpull(EXYNOS4_GPX0(4), S3C_GPIO_PULL_NONE); +} + static void __init origen_machine_init(void) { + origen_power_init(); + + s3c_i2c0_set_platdata(NULL); + i2c_register_board_info(0, i2c0_devs, ARRAY_SIZE(i2c0_devs)); + /* * Since sdhci instance 2 can contain a bootable media, * sdhci instance 0 is registered after instance 2. From 9421a76d2bfec62b89b395033d03eea44bb2a4ac Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Mon, 3 Oct 2011 09:12:56 +0900 Subject: [PATCH 0516/1596] ARM: EXYNOS4: Add machine support for 7" LCD on ORIGEN ORIGEN board is fitted with 7" LCD panel HV070WSA. The pixel resolution of the LCD panel is 1024x600. Also power domain device for LCD0 is registered. Signed-off-by: Tushar Behera Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/Kconfig | 5 ++- arch/arm/mach-exynos4/mach-origen.c | 63 ++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 257dbaaf149b..6fc17228a636 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -229,11 +229,14 @@ config MACH_ORIGEN select S5P_DEV_FIMC1 select S5P_DEV_FIMC2 select S5P_DEV_FIMC3 + select S5P_DEV_FIMD0 select S5P_DEV_I2C_HDMIPHY - select S5P_DEV_USB_EHCI select S5P_DEV_TV + select S5P_DEV_USB_EHCI + select EXYNOS4_DEV_PD select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_PWM + select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_SDHCI select EXYNOS4_SETUP_USB_PHY help diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c index 3da77766961e..349e2977b2ed 100644 --- a/arch/arm/mach-exynos4/mach-origen.c +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -19,11 +19,15 @@ #include #include #include +#include #include #include +#include Flash API. + + &VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls. + diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index c57d1ec6291c..3f47df1aa54a 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -927,6 +927,33 @@ ioctl is called. Applications set or clear this flag before calling the VIDIOC_QBUF ioctl. + + V4L2_BUF_FLAG_PREPARED + 0x0400 + The buffer has been prepared for I/O and can be queued by the +application. Drivers set or clear this flag when the +VIDIOC_QUERYBUF, VIDIOC_PREPARE_BUF, VIDIOC_QBUF or VIDIOC_DQBUF ioctl is called. + + + V4L2_BUF_FLAG_NO_CACHE_INVALIDATE + 0x0400 + Caches do not have to be invalidated for this buffer. +Typically applications shall use this flag if the data captured in the buffer +is not going to be touched by the CPU, instead the buffer will, probably, be +passed on to a DMA-capable hardware unit for further processing or output. + + + + V4L2_BUF_FLAG_NO_CACHE_CLEAN + 0x0800 + Caches do not have to be cleaned for this buffer. +Typically applications shall use this flag for output buffers if the data +in this buffer has not been created by the CPU but by some DMA-capable unit, +in which case caches have not been used. + diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 40132c277647..2ab365c10fb9 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -469,6 +469,7 @@ and discussions on the V4L mailing list. &sub-close; &sub-ioctl; + &sub-create-bufs; &sub-cropcap; &sub-dbg-g-chip-ident; &sub-dbg-g-register; @@ -511,6 +512,7 @@ and discussions on the V4L mailing list. &sub-queryctrl; &sub-query-dv-preset; &sub-querystd; + &sub-prepare-buf; &sub-reqbufs; &sub-s-hw-freq-seek; &sub-streamon; diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml new file mode 100644 index 000000000000..73ae8a6cd004 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml @@ -0,0 +1,139 @@ + + + ioctl VIDIOC_CREATE_BUFS + &manvol; + + + + VIDIOC_CREATE_BUFS + Create buffers for Memory Mapped or User Pointer I/O + + + + + + int ioctl + int fd + int request + struct v4l2_create_buffers *argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_CREATE_BUFS + + + + argp + + + + + + + + + Description + + This ioctl is used to create buffers for memory +mapped or user pointer +I/O. It can be used as an alternative or in addition to the +VIDIOC_REQBUFS ioctl, when a tighter control over buffers +is required. This ioctl can be called multiple times to create buffers of +different sizes. + + To allocate device buffers applications initialize relevant fields of +the v4l2_create_buffers structure. They set the +type field in the +v4l2_format structure, embedded in this +structure, to the respective stream or buffer type. +count must be set to the number of required buffers. +memory specifies the required I/O method. The +format field shall typically be filled in using +either the VIDIOC_TRY_FMT or +VIDIOC_G_FMT ioctl(). Additionally, applications can adjust +sizeimage fields to fit their specific needs. The +reserved array must be zeroed. + + When the ioctl is called with a pointer to this structure the driver +will attempt to allocate up to the requested number of buffers and store the +actual number allocated and the starting index in the +count and the index fields +respectively. On return count can be smaller than +the number requested. The driver may also increase buffer sizes if required, +however, it will not update sizeimage field values. +The user has to use VIDIOC_QUERYBUF to retrieve that +information. + + + struct <structname>v4l2_create_buffers</structname> + + &cs-str; + + + __u32 + index + The starting buffer index, returned by the driver. + + + __u32 + count + The number of buffers requested or granted. + + + &v4l2-memory; + memory + Applications set this field to +V4L2_MEMORY_MMAP or +V4L2_MEMORY_USERPTR. + + + &v4l2-format; + format + Filled in by the application, preserved by the driver. + + + __u32 + reserved[8] + A place holder for future extensions. + + + +
+
+ + + &return-value; + + + + ENOMEM + + No memory to allocate buffers for memory +mapped I/O. + + + + EINVAL + + The buffer type (type field) or the +requested I/O method (memory) is not +supported. + + + + +
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml new file mode 100644 index 000000000000..7bde698760e4 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml @@ -0,0 +1,88 @@ + + + ioctl VIDIOC_PREPARE_BUF + &manvol; + + + + VIDIOC_PREPARE_BUF + Prepare a buffer for I/O + + + + + + int ioctl + int fd + int request + struct v4l2_buffer *argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_PREPARE_BUF + + + + argp + + + + + + + + + Description + + Applications can optionally call the +VIDIOC_PREPARE_BUF ioctl to pass ownership of the buffer +to the driver before actually enqueuing it, using the +VIDIOC_QBUF ioctl, and to prepare it for future I/O. +Such preparations may include cache invalidation or cleaning. Performing them +in advance saves time during the actual I/O. In case such cache operations are +not required, the application can use one of +V4L2_BUF_FLAG_NO_CACHE_INVALIDATE and +V4L2_BUF_FLAG_NO_CACHE_CLEAN flags to skip the respective +step. + + The v4l2_buffer structure is +specified in . + + + + &return-value; + + + + EBUSY + + File I/O is in progress. + + + + EINVAL + + The buffer type is not +supported, or the index is out of bounds, +or no buffers have been allocated yet, or the +userptr or +length are invalid. + + + + + From fc714e70dd063e6887d09872ac6158b0c20cc817 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Aug 2011 10:30:21 -0300 Subject: [PATCH 1327/1596] [media] V4L: vb2: prepare to support multi-size buffers In preparation for the forthcoming VIDIOC_CREATE_BUFS ioctl add a "const struct v4l2_format *" argument to the .queue_setup() vb2 operation. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/atmel-isi.c | 6 +++--- drivers/media/video/marvell-ccic/mcam-core.c | 3 ++- drivers/media/video/mem2mem_testdev.c | 7 ++++--- drivers/media/video/mx3_camera.c | 1 + drivers/media/video/pwc/pwc-if.c | 6 +++--- drivers/media/video/s5p-fimc/fimc-capture.c | 6 +++--- drivers/media/video/s5p-fimc/fimc-core.c | 6 +++--- drivers/media/video/s5p-mfc/s5p_mfc_dec.c | 7 ++++--- drivers/media/video/s5p-mfc/s5p_mfc_enc.c | 5 +++-- drivers/media/video/s5p-tv/mixer_video.c | 4 ++-- drivers/media/video/sh_mobile_ceu_camera.c | 1 + drivers/media/video/videobuf2-core.c | 6 +++--- drivers/media/video/vivi.c | 6 +++--- include/media/videobuf2-core.h | 6 +++--- 14 files changed, 38 insertions(+), 32 deletions(-) diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 06f6595a1c9a..8c775c59e120 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -249,9 +249,9 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 1141b976dff4..80ec64d2d6d8 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c @@ -883,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam) * Videobuf2 interface code. */ -static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, +static int mcam_vb_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *nbufs, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index 9594b52f8605..12897e8a3314 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -738,9 +738,10 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { * Queue operations */ -static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) +static int m2mtest_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); struct m2mtest_q_data *q_data; diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index f4ef6b993ff1..24c2fe0714c5 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -191,6 +191,7 @@ static void mx3_cam_dma_done(void *arg) * Calculate the __buffer__ (not data) size and number of buffers. */ static int mx3_videobuf_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 360be226718d..01ff643e682d 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -744,9 +744,9 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) /***************************************************************************/ /* Videobuf2 operations */ -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { struct pwc_device *pdev = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 931f469604b0..c8d91b0cd9bd 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -246,9 +246,9 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; } -static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - void *allocators[]) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) { struct fimc_ctx *ctx = vq->drv_priv; struct fimc_fmt *fmt = ctx->d_frame.fmt; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6c1c9cb55378..19ca6db38b2f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -670,9 +670,9 @@ static void fimc_job_abort(void *priv) fimc_m2m_shutdown(priv); } -static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - void *allocators[]) +static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) { struct fimc_ctx *ctx = vb2_get_drv_priv(vq); struct fimc_frame *f; diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index bfbe08432050..725634d9736d 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -744,9 +744,10 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { .vidioc_g_crop = vidioc_g_crop, }; -static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, - unsigned int *plane_count, unsigned int psize[], - void *allocators[]) +static int s5p_mfc_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *buf_count, + unsigned int *plane_count, unsigned int psize[], + void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index 4c90e53bd964..ecef127dbc66 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -1513,8 +1513,9 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) } static int s5p_mfc_queue_setup(struct vb2_queue *vq, - unsigned int *buf_count, unsigned int *plane_count, - unsigned int psize[], void *allocators[]) + const struct v4l2_format *fmt, + unsigned int *buf_count, unsigned int *plane_count, + unsigned int psize[], void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index 4917e2c2b321..e16d3a4bc1dc 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -727,8 +727,8 @@ static const struct v4l2_file_operations mxr_fops = { .unlocked_ioctl = video_ioctl2, }; -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, + unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct mxr_layer *layer = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 5c8ddd821df6..0cb19689cfe8 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -193,6 +193,7 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) * Videobuf operations */ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 82b51be3ca72..f04f27d68cec 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -530,7 +530,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * Ask the driver how many buffers and planes per buffer it requires. * Driver also sets the size and allocator context for each plane. */ - ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, + ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); if (ret) return ret; @@ -549,8 +549,8 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) unsigned int orig_num_buffers; orig_num_buffers = num_buffers = ret; - ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, - q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, NULL, &num_buffers, + &num_planes, q->plane_sizes, q->alloc_ctx); if (ret) goto free_mem; diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 7cf94c09d99a..7d754fbcccbf 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -650,9 +650,9 @@ static void vivi_stop_generating(struct vivi_dev *dev) /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { struct vivi_dev *dev = vb2_get_drv_priv(vq); unsigned long size; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index dbd10acc8e80..692e35c232a9 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -218,9 +218,9 @@ struct vb2_buffer { * pre-queued buffers before calling STREAMON */ struct vb2_ops { - int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - void *alloc_ctxs[]); + int (*queue_setup)(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]); void (*wait_prepare)(struct vb2_queue *q); void (*wait_finish)(struct vb2_queue *q); From 2d86401c2cbfce9f99b08ba168bdb60b2eb7796e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 28 Sep 2011 09:23:02 -0300 Subject: [PATCH 1328/1596] [media] V4L: vb2: add support for buffers of different sizes on a single queue The two recently added ioctl()s VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF allow user-space applications to allocate video buffers of different sizes and hand them over to the driver for fast switching between different frame formats. This patch adds support for buffers of different sizes on the same buffer-queue to vb2. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 294 ++++++++++++++++++++++----- include/media/videobuf2-core.h | 35 ++-- 2 files changed, 270 insertions(+), 59 deletions(-) diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index f04f27d68cec..9005dc9991ab 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -38,7 +38,8 @@ module_param(debug, int, 0644); (((q)->ops->op) ? ((q)->ops->op(args)) : 0) #define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ - V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR) + V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \ + V4L2_BUF_FLAG_PREPARED) /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer @@ -109,13 +110,22 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) * __setup_offsets() - setup unique offsets ("cookies") for every plane in * every buffer on the queue */ -static void __setup_offsets(struct vb2_queue *q) +static void __setup_offsets(struct vb2_queue *q, unsigned int n) { unsigned int buffer, plane; struct vb2_buffer *vb; - unsigned long off = 0; + unsigned long off; - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + if (q->num_buffers) { + struct v4l2_plane *p; + vb = q->bufs[q->num_buffers - 1]; + p = &vb->v4l2_planes[vb->num_planes - 1]; + off = PAGE_ALIGN(p->m.mem_offset + p->length); + } else { + off = 0; + } + + for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) { vb = q->bufs[buffer]; if (!vb) continue; @@ -161,7 +171,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, vb->state = VB2_BUF_STATE_DEQUEUED; vb->vb2_queue = q; vb->num_planes = num_planes; - vb->v4l2_buf.index = buffer; + vb->v4l2_buf.index = q->num_buffers + buffer; vb->v4l2_buf.type = q->type; vb->v4l2_buf.memory = memory; @@ -189,15 +199,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, } } - q->bufs[buffer] = vb; + q->bufs[q->num_buffers + buffer] = vb; } - q->num_buffers = buffer; - - __setup_offsets(q); + __setup_offsets(q, buffer); dprintk(1, "Allocated %d buffers, %d plane(s) each\n", - q->num_buffers, num_planes); + buffer, num_planes); return buffer; } @@ -205,12 +213,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, /** * __vb2_free_mem() - release all video buffer memory for a given queue */ -static void __vb2_free_mem(struct vb2_queue *q) +static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) { unsigned int buffer; struct vb2_buffer *vb; - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + ++buffer) { vb = q->bufs[buffer]; if (!vb) continue; @@ -224,17 +233,18 @@ static void __vb2_free_mem(struct vb2_queue *q) } /** - * __vb2_queue_free() - free the queue - video memory and related information - * and return the queue to an uninitialized state. Might be called even if the - * queue has already been freed. + * __vb2_queue_free() - free buffers at the end of the queue - video memory and + * related information, if no buffers are left return the queue to an + * uninitialized state. Might be called even if the queue has already been freed. */ -static void __vb2_queue_free(struct vb2_queue *q) +static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) { unsigned int buffer; /* Call driver-provided cleanup function for each buffer, if provided */ if (q->ops->buf_cleanup) { - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + ++buffer) { if (NULL == q->bufs[buffer]) continue; q->ops->buf_cleanup(q->bufs[buffer]); @@ -242,23 +252,25 @@ static void __vb2_queue_free(struct vb2_queue *q) } /* Release video buffer memory */ - __vb2_free_mem(q); + __vb2_free_mem(q, buffers); /* Free videobuf buffers */ - for (buffer = 0; buffer < q->num_buffers; ++buffer) { + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; + ++buffer) { kfree(q->bufs[buffer]); q->bufs[buffer] = NULL; } - q->num_buffers = 0; - q->memory = 0; + q->num_buffers -= buffers; + if (!q->num_buffers) + q->memory = 0; } /** * __verify_planes_array() - verify that the planes array passed in struct * v4l2_buffer from userspace can be safely used */ -static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) { /* Is memory for copying plane information present? */ if (NULL == b->m.planes) { @@ -318,7 +330,7 @@ static bool __buffers_in_use(struct vb2_queue *q) static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; - int ret = 0; + int ret; /* Copy back data such as timestamp, flags, input, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); @@ -365,8 +377,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) case VB2_BUF_STATE_DONE: b->flags |= V4L2_BUF_FLAG_DONE; break; - case VB2_BUF_STATE_DEQUEUED: case VB2_BUF_STATE_PREPARED: + b->flags |= V4L2_BUF_FLAG_PREPARED; + break; + case VB2_BUF_STATE_DEQUEUED: /* nothing */ break; } @@ -374,7 +388,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) if (__buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; - return ret; + return 0; } /** @@ -460,7 +474,7 @@ static int __verify_mmap_ops(struct vb2_queue *q) */ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) { - unsigned int num_buffers, num_planes; + unsigned int num_buffers, allocated_buffers, num_planes = 0; int ret = 0; if (q->fileio) { @@ -508,7 +522,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EBUSY; } - __vb2_queue_free(q); + __vb2_queue_free(q, q->num_buffers); /* * In case of REQBUFS(0) return immediately without calling @@ -542,43 +556,167 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -ENOMEM; } + allocated_buffers = ret; + /* * Check if driver can handle the allocated number of buffers. */ - if (ret < num_buffers) { - unsigned int orig_num_buffers; + if (allocated_buffers < num_buffers) { + num_buffers = allocated_buffers; - orig_num_buffers = num_buffers = ret; ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); - if (ret) - goto free_mem; - if (orig_num_buffers < num_buffers) { + if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; - goto free_mem; - } /* - * Ok, driver accepted smaller number of buffers. + * Either the driver has accepted a smaller number of buffers, + * or .queue_setup() returned an error */ - ret = num_buffers; + } + + q->num_buffers = allocated_buffers; + + if (ret < 0) { + __vb2_queue_free(q, allocated_buffers); + return ret; } /* * Return the number of successfully allocated buffers * to the userspace. */ - req->count = ret; + req->count = allocated_buffers; return 0; - -free_mem: - __vb2_queue_free(q); - return ret; } EXPORT_SYMBOL_GPL(vb2_reqbufs); +/** + * vb2_create_bufs() - Allocate buffers and any required auxiliary structs + * @q: videobuf2 queue + * @create: creation parameters, passed from userspace to vidioc_create_bufs + * handler in driver + * + * Should be called from vidioc_create_bufs ioctl handler of a driver. + * This function: + * 1) verifies parameter sanity + * 2) calls the .queue_setup() queue operation + * 3) performs any necessary memory allocations + * + * The return values from this function are intended to be directly returned + * from vidioc_create_bufs handler in driver. + */ +int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) +{ + unsigned int num_planes = 0, num_buffers, allocated_buffers; + int ret = 0; + + if (q->fileio) { + dprintk(1, "%s(): file io in progress\n", __func__); + return -EBUSY; + } + + if (create->memory != V4L2_MEMORY_MMAP + && create->memory != V4L2_MEMORY_USERPTR) { + dprintk(1, "%s(): unsupported memory type\n", __func__); + return -EINVAL; + } + + if (create->format.type != q->type) { + dprintk(1, "%s(): requested type is incorrect\n", __func__); + return -EINVAL; + } + + /* + * Make sure all the required memory ops for given memory type + * are available. + */ + if (create->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { + dprintk(1, "%s(): MMAP for current setup unsupported\n", __func__); + return -EINVAL; + } + + if (create->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { + dprintk(1, "%s(): USERPTR for current setup unsupported\n", __func__); + return -EINVAL; + } + + if (q->num_buffers == VIDEO_MAX_FRAME) { + dprintk(1, "%s(): maximum number of buffers already allocated\n", + __func__); + return -ENOBUFS; + } + + create->index = q->num_buffers; + + if (!q->num_buffers) { + memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); + memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + q->memory = create->memory; + } + + num_buffers = min(create->count, VIDEO_MAX_FRAME - q->num_buffers); + + /* + * Ask the driver, whether the requested number of buffers, planes per + * buffer and their sizes are acceptable + */ + ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, + &num_planes, q->plane_sizes, q->alloc_ctx); + if (ret) + return ret; + + /* Finally, allocate buffers and video memory */ + ret = __vb2_queue_alloc(q, create->memory, num_buffers, + num_planes); + if (ret < 0) { + dprintk(1, "Memory allocation failed with error: %d\n", ret); + return ret; + } + + allocated_buffers = ret; + + /* + * Check if driver can handle the so far allocated number of buffers. + */ + if (ret < num_buffers) { + num_buffers = ret; + + /* + * q->num_buffers contains the total number of buffers, that the + * queue driver has set up + */ + ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, + &num_planes, q->plane_sizes, q->alloc_ctx); + + if (!ret && allocated_buffers < num_buffers) + ret = -ENOMEM; + + /* + * Either the driver has accepted a smaller number of buffers, + * or .queue_setup() returned an error + */ + } + + q->num_buffers += allocated_buffers; + + if (ret < 0) { + __vb2_queue_free(q, allocated_buffers); + return ret; + } + + /* + * Return the number of successfully allocated buffers + * to the userspace. + */ + create->count = allocated_buffers; + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_create_bufs); + /** * vb2_plane_vaddr() - Return a kernel virtual address of a given plane * @vb: vb2_buffer to which the plane in question belongs to @@ -663,7 +801,7 @@ EXPORT_SYMBOL_GPL(vb2_buffer_done); * __fill_vb2_buffer() - fill a vb2_buffer with information provided in * a v4l2_buffer by the userspace */ -static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, +static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, struct v4l2_plane *v4l2_planes) { unsigned int plane; @@ -727,7 +865,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, /** * __qbuf_userptr() - handle qbuf of a USERPTR buffer */ -static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) { struct v4l2_plane planes[VIDEO_MAX_PLANES]; struct vb2_queue *q = vb->vb2_queue; @@ -816,7 +954,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) /** * __qbuf_mmap() - handle qbuf of an MMAP buffer */ -static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) { return __fill_vb2_buffer(vb, b, vb->v4l2_planes); } @@ -833,7 +971,7 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) q->ops->buf_queue(vb); } -static int __buf_prepare(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; int ret; @@ -860,6 +998,68 @@ static int __buf_prepare(struct vb2_buffer *vb, struct v4l2_buffer *b) return ret; } +/** + * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel + * @q: videobuf2 queue + * @b: buffer structure passed from userspace to vidioc_prepare_buf + * handler in driver + * + * Should be called from vidioc_prepare_buf ioctl handler of a driver. + * This function: + * 1) verifies the passed buffer, + * 2) calls buf_prepare callback in the driver (if provided), in which + * driver-specific buffer initialization can be performed, + * + * The return values from this function are intended to be directly returned + * from vidioc_prepare_buf handler in driver. + */ +int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) +{ + struct vb2_buffer *vb; + int ret; + + if (q->fileio) { + dprintk(1, "%s(): file io in progress\n", __func__); + return -EBUSY; + } + + if (b->type != q->type) { + dprintk(1, "%s(): invalid buffer type\n", __func__); + return -EINVAL; + } + + if (b->index >= q->num_buffers) { + dprintk(1, "%s(): buffer index out of range\n", __func__); + return -EINVAL; + } + + vb = q->bufs[b->index]; + if (NULL == vb) { + /* Should never happen */ + dprintk(1, "%s(): buffer is NULL\n", __func__); + return -EINVAL; + } + + if (b->memory != q->memory) { + dprintk(1, "%s(): invalid memory type\n", __func__); + return -EINVAL; + } + + if (vb->state != VB2_BUF_STATE_DEQUEUED) { + dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); + return -EINVAL; + } + + ret = __buf_prepare(vb, b); + if (ret < 0) + return ret; + + __fill_v4l2_buffer(vb, b); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_prepare_buf); + /** * vb2_qbuf() - Queue a buffer from userspace * @q: videobuf2 queue @@ -1484,7 +1684,7 @@ void vb2_queue_release(struct vb2_queue *q) { __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); - __vb2_queue_free(q); + __vb2_queue_free(q, q->num_buffers); } EXPORT_SYMBOL_GPL(vb2_queue_release); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 692e35c232a9..55c57d3d3e63 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -169,13 +169,21 @@ struct vb2_buffer { /** * struct vb2_ops - driver-specific callbacks * - * @queue_setup: called from a VIDIOC_REQBUFS handler, before - * memory allocation; driver should return the required - * number of buffers in num_buffers, the required number - * of planes per buffer in num_planes; the size of each - * plane should be set in the sizes[] array and optional - * per-plane allocator specific context in alloc_ctxs[] - * array + * @queue_setup: called from VIDIOC_REQBUFS and VIDIOC_CREATE_BUFS + * handlers before memory allocation, or, if + * *num_planes != 0, after the allocation to verify a + * smaller number of buffers. Driver should return + * the required number of buffers in *num_buffers, the + * required number of planes per buffer in *num_planes; the + * size of each plane should be set in the sizes[] array + * and optional per-plane allocator specific context in the + * alloc_ctxs[] array. When called from VIDIOC_REQBUFS, + * fmt == NULL, the driver has to use the currently + * configured format and *num_buffers is the total number + * of buffers, that are being allocated. When called from + * VIDIOC_CREATE_BUFS, fmt != NULL and it describes the + * target frame format. In this case *num_buffers are being + * allocated additionally to q->num_buffers. * @wait_prepare: release any locks taken while calling vb2 functions; * it is called before an ioctl needs to wait for a new * buffer to arrive; required to avoid a deadlock in @@ -188,11 +196,11 @@ struct vb2_buffer { * perform additional buffer-related initialization; * initialization failure (return != 0) will prevent * queue setup from completing successfully; optional - * @buf_prepare: called every time the buffer is queued from userspace; - * drivers may perform any initialization required before - * each hardware operation in this callback; - * if an error is returned, the buffer will not be queued - * in driver; optional + * @buf_prepare: called every time the buffer is queued from userspace + * and from the VIDIOC_PREPARE_BUF ioctl; drivers may + * perform any initialization required before each hardware + * operation in this callback; if an error is returned, the + * buffer will not be queued in driver; optional * @buf_finish: called before every dequeue of the buffer back to * userspace; drivers may perform any operations required * before userspace accesses the buffer; optional @@ -300,6 +308,9 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q); int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b); int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req); +int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create); +int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b); + int vb2_queue_init(struct vb2_queue *q); void vb2_queue_release(struct vb2_queue *q); From 1d3564d91f94d0b598304eb6ebe3b83a83176f7a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 25 Aug 2011 13:26:53 -0300 Subject: [PATCH 1329/1596] [media] dmaengine: ipu-idmac: add support for the DMA_PAUSE control To support multi-size buffers in the mx3_camera V4L2 driver we have to be able to stop DMA on a channel without releasing descriptors and completely halting the hardware. Use the DMA_PAUSE control to implement this mode. Signed-off-by: Guennadi Liakhovetski Acked-by: Vinod Koul Signed-off-by: Mauro Carvalho Chehab --- drivers/dma/ipu/ipu_idmac.c | 65 ++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index 6815905a772f..ddc2a1331822 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -1307,6 +1307,7 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id) ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) { callback = descnew->txd.callback; callback_param = descnew->txd.callback_param; + list_del_init(&descnew->list); spin_unlock(&ichan->lock); if (callback) callback(callback_param); @@ -1428,39 +1429,58 @@ static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, { struct idmac_channel *ichan = to_idmac_chan(chan); struct idmac *idmac = to_idmac(chan->device); + struct ipu *ipu = to_ipu(idmac); + struct list_head *list, *tmp; unsigned long flags; int i; - /* Only supports DMA_TERMINATE_ALL */ - if (cmd != DMA_TERMINATE_ALL) - return -ENXIO; + switch (cmd) { + case DMA_PAUSE: + spin_lock_irqsave(&ipu->lock, flags); + ipu_ic_disable_task(ipu, chan->chan_id); - ipu_disable_channel(idmac, ichan, - ichan->status >= IPU_CHANNEL_ENABLED); + /* Return all descriptors into "prepared" state */ + list_for_each_safe(list, tmp, &ichan->queue) + list_del_init(list); - tasklet_disable(&to_ipu(idmac)->tasklet); + ichan->sg[0] = NULL; + ichan->sg[1] = NULL; - /* ichan->queue is modified in ISR, have to spinlock */ - spin_lock_irqsave(&ichan->lock, flags); - list_splice_init(&ichan->queue, &ichan->free_list); + spin_unlock_irqrestore(&ipu->lock, flags); - if (ichan->desc) - for (i = 0; i < ichan->n_tx_desc; i++) { - struct idmac_tx_desc *desc = ichan->desc + i; - if (list_empty(&desc->list)) - /* Descriptor was prepared, but not submitted */ - list_add(&desc->list, &ichan->free_list); + ichan->status = IPU_CHANNEL_INITIALIZED; + break; + case DMA_TERMINATE_ALL: + ipu_disable_channel(idmac, ichan, + ichan->status >= IPU_CHANNEL_ENABLED); - async_tx_clear_ack(&desc->txd); - } + tasklet_disable(&ipu->tasklet); - ichan->sg[0] = NULL; - ichan->sg[1] = NULL; - spin_unlock_irqrestore(&ichan->lock, flags); + /* ichan->queue is modified in ISR, have to spinlock */ + spin_lock_irqsave(&ichan->lock, flags); + list_splice_init(&ichan->queue, &ichan->free_list); - tasklet_enable(&to_ipu(idmac)->tasklet); + if (ichan->desc) + for (i = 0; i < ichan->n_tx_desc; i++) { + struct idmac_tx_desc *desc = ichan->desc + i; + if (list_empty(&desc->list)) + /* Descriptor was prepared, but not submitted */ + list_add(&desc->list, &ichan->free_list); - ichan->status = IPU_CHANNEL_INITIALIZED; + async_tx_clear_ack(&desc->txd); + } + + ichan->sg[0] = NULL; + ichan->sg[1] = NULL; + spin_unlock_irqrestore(&ichan->lock, flags); + + tasklet_enable(&ipu->tasklet); + + ichan->status = IPU_CHANNEL_INITIALIZED; + break; + default: + return -ENOSYS; + } return 0; } @@ -1663,7 +1683,6 @@ static void __exit ipu_idmac_exit(struct ipu *ipu) struct idmac_channel *ichan = ipu->channel + i; idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0); - idmac_prep_slave_sg(&ichan->dma_chan, NULL, 0, DMA_NONE, 0); } dma_async_device_unregister(&idmac->dma); From ee02da64558f04fb30c2462fdeabdfafc87a9799 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 6 Sep 2011 12:36:39 -0300 Subject: [PATCH 1330/1596] [media] soc_camera: add control handler support The soc_camera framework is switched over to use the control framework. After this patch none of the controls in subdevs or host drivers are available, until those drivers are also converted to the control framework. Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: moved code around, fixed problems] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 94 +++++++------------------------- include/media/soc_camera.h | 2 + 2 files changed, 21 insertions(+), 75 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index ac23916552db..b56f4b78273d 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -512,6 +512,7 @@ static int soc_camera_open(struct file *file) if (ret < 0) goto einitvb; } + v4l2_ctrl_handler_setup(&icd->ctrl_handler); } file->private_data = icd; @@ -781,78 +782,6 @@ static int soc_camera_streamoff(struct file *file, void *priv, return 0; } -static int soc_camera_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - int i; - - WARN_ON(priv != file->private_data); - - if (!qc->id) - return -EINVAL; - - /* First check host controls */ - for (i = 0; i < ici->ops->num_controls; i++) - if (qc->id == ici->ops->controls[i].id) { - memcpy(qc, &(ici->ops->controls[i]), - sizeof(*qc)); - return 0; - } - - if (!icd->ops) - return -EINVAL; - - /* Then device controls */ - for (i = 0; i < icd->ops->num_controls; i++) - if (qc->id == icd->ops->controls[i].id) { - memcpy(qc, &(icd->ops->controls[i]), - sizeof(*qc)); - return 0; - } - - return -EINVAL; -} - -static int soc_camera_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (ici->ops->get_ctrl) { - ret = ici->ops->get_ctrl(icd, ctrl); - if (ret != -ENOIOCTLCMD) - return ret; - } - - return v4l2_subdev_call(sd, core, g_ctrl, ctrl); -} - -static int soc_camera_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (ici->ops->set_ctrl) { - ret = ici->ops->set_ctrl(icd, ctrl); - if (ret != -ENOIOCTLCMD) - return ret; - } - - return v4l2_subdev_call(sd, core, s_ctrl, ctrl); -} - static int soc_camera_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a) { @@ -1055,6 +984,17 @@ static int soc_camera_probe(struct soc_camera_device *icd) dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); + /* + * Currently the subdev with the largest number of controls (13) is + * ov6550. So let's pick 16 as a hint for the control handler. Note + * that this is a hint only: too large and you waste some memory, too + * small and there is a (very) small performance hit when looking up + * controls in the internal hash. + */ + ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16); + if (ret < 0) + return ret; + ret = regulator_bulk_get(icd->pdev, icl->num_regulators, icl->regulators); if (ret < 0) @@ -1108,6 +1048,9 @@ static int soc_camera_probe(struct soc_camera_device *icd) sd = soc_camera_to_subdev(icd); sd->grp_id = (long)icd; + if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler)) + goto ectrl; + /* At this point client .probe() should have run already */ ret = soc_camera_init_user_formats(icd); if (ret < 0) @@ -1146,6 +1089,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) mutex_unlock(&icd->video_lock); soc_camera_free_user_formats(icd); eiufmt: +ectrl: if (icl->board_info) { soc_camera_free_i2c(icd); } else { @@ -1162,6 +1106,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) epower: regulator_bulk_free(icl->num_regulators, icl->regulators); ereg: + v4l2_ctrl_handler_free(&icd->ctrl_handler); return ret; } @@ -1176,6 +1121,7 @@ static int soc_camera_remove(struct soc_camera_device *icd) BUG_ON(!icd->parent); + v4l2_ctrl_handler_free(&icd->ctrl_handler); if (vdev) { video_unregister_device(vdev); icd->vdev = NULL; @@ -1381,9 +1327,6 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_dqbuf = soc_camera_dqbuf, .vidioc_streamon = soc_camera_streamon, .vidioc_streamoff = soc_camera_streamoff, - .vidioc_queryctrl = soc_camera_queryctrl, - .vidioc_g_ctrl = soc_camera_g_ctrl, - .vidioc_s_ctrl = soc_camera_s_ctrl, .vidioc_cropcap = soc_camera_cropcap, .vidioc_g_crop = soc_camera_g_crop, .vidioc_s_crop = soc_camera_s_crop, @@ -1412,6 +1355,7 @@ static int video_dev_create(struct soc_camera_device *icd) vdev->ioctl_ops = &soc_camera_ioctl_ops; vdev->release = video_device_release; vdev->tvnorms = V4L2_STD_UNKNOWN; + vdev->ctrl_handler = &icd->ctrl_handler; vdev->lock = &icd->video_lock; icd->vdev = vdev; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 1864e2242d45..2e15e17130da 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -19,6 +19,7 @@ #include #include #include +#include #include struct file; @@ -40,6 +41,7 @@ struct soc_camera_device { struct soc_camera_sense *sense; /* See comment in struct definition */ struct soc_camera_ops *ops; struct video_device *vdev; + struct v4l2_ctrl_handler ctrl_handler; const struct soc_camera_format_xlate *current_fmt; struct soc_camera_format_xlate *user_formats; int num_user_formats; From d34bfcd2a1e5f6be5ae81030b7a6193094632955 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 5 Sep 2011 17:07:47 -0300 Subject: [PATCH 1331/1596] [media] sh_mobile_ceu_camera: implement the control handler And since this is the last and only host driver that uses controls, also remove the now obsolete control fields from soc_camera.h. Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: moved code around, fixed problems] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 91 +++++++++------------- include/media/soc_camera.h | 4 - 2 files changed, 38 insertions(+), 57 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 0cb19689cfe8..5d5781bd1447 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -951,6 +951,38 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); +static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct soc_camera_device, + ctrl_handler); +} + +static int sh_mobile_ceu_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct soc_camera_device *icd = ctrl_to_icd(ctrl); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + + switch (ctrl->id) { + case V4L2_CID_SHARPNESS: + switch (icd->current_fmt->host_fmt->fourcc) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + ceu_write(pcdev, CLFCR, !ctrl->val); + return 0; + } + break; + } + + return -EINVAL; +} + +static const struct v4l2_ctrl_ops sh_mobile_ceu_ctrl_ops = { + .s_ctrl = sh_mobile_ceu_s_ctrl, +}; + static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { @@ -987,6 +1019,12 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int struct v4l2_rect rect; int shift = 0; + /* Add our control */ + v4l2_ctrl_new_std(&icd->ctrl_handler, &sh_mobile_ceu_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 1, 1, 0); + if (icd->ctrl_handler.error) + return icd->ctrl_handler.error; + /* FIXME: subwindow is lost between close / open */ /* Cache current client geometry */ @@ -1915,55 +1953,6 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, return vb2_queue_init(q); } -static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd, - struct v4l2_control *ctrl) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - u32 val; - - switch (ctrl->id) { - case V4L2_CID_SHARPNESS: - val = ceu_read(pcdev, CLFCR); - ctrl->value = val ^ 1; - return 0; - } - return -ENOIOCTLCMD; -} - -static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, - struct v4l2_control *ctrl) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - switch (ctrl->id) { - case V4L2_CID_SHARPNESS: - switch (icd->current_fmt->host_fmt->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - ceu_write(pcdev, CLFCR, !ctrl->value); - return 0; - } - return -EINVAL; - } - return -ENOIOCTLCMD; -} - -static const struct v4l2_queryctrl sh_mobile_ceu_controls[] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Low-pass filter", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { .owner = THIS_MODULE, .add = sh_mobile_ceu_add_device, @@ -1975,14 +1964,10 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { .set_livecrop = sh_mobile_ceu_set_livecrop, .set_fmt = sh_mobile_ceu_set_fmt, .try_fmt = sh_mobile_ceu_try_fmt, - .set_ctrl = sh_mobile_ceu_set_ctrl, - .get_ctrl = sh_mobile_ceu_get_ctrl, .poll = sh_mobile_ceu_poll, .querycap = sh_mobile_ceu_querycap, .set_bus_param = sh_mobile_ceu_set_bus_param, .init_videobuf2 = sh_mobile_ceu_init_videobuf, - .controls = sh_mobile_ceu_controls, - .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls), }; struct bus_wait { diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 2e15e17130da..d41b8bd74445 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -96,14 +96,10 @@ struct soc_camera_host_ops { int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *); int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); int (*set_bus_param)(struct soc_camera_device *, __u32); - int (*get_ctrl)(struct soc_camera_device *, struct v4l2_control *); - int (*set_ctrl)(struct soc_camera_device *, struct v4l2_control *); int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *); int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *); int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *); unsigned int (*poll)(struct file *, poll_table *); - const struct v4l2_queryctrl *controls; - int num_controls; }; #define SOCAM_SENSOR_INVERT_PCLK (1 << 0) From 839b48dff10990c03f7d41afdaf5853cb3c0ab83 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 09:49:30 -0300 Subject: [PATCH 1332/1596] [media] ov9640: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov9640.c | 119 +++++++++++------------------------ drivers/media/video/ov9640.h | 4 +- 2 files changed, 38 insertions(+), 85 deletions(-) diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 352a8fb68b84..12d33a9c07b0 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "ov9640.h" @@ -164,27 +165,6 @@ static enum v4l2_mbus_pixelcode ov9640_codes[] = { V4L2_MBUS_FMT_RGB565_2X8_LE, }; -static const struct v4l2_queryctrl ov9640_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - /* read a register */ static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) { @@ -286,52 +266,25 @@ static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -/* Get status of additional camera capabilities */ -static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - } - return 0; -} - /* Set status of additional camera capabilities */ -static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov9640_priv *priv = to_ov9640_sensor(sd); - - int ret = 0; + struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); + struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); switch (ctrl->id) { case V4L2_CID_VFLIP: - priv->flag_vflip = ctrl->value; - if (ctrl->value) - ret = ov9640_reg_rmw(client, OV9640_MVFP, + if (ctrl->val) + return ov9640_reg_rmw(client, OV9640_MVFP, OV9640_MVFP_V, 0); - else - ret = ov9640_reg_rmw(client, OV9640_MVFP, - 0, OV9640_MVFP_V); - break; + return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); case V4L2_CID_HFLIP: - priv->flag_hflip = ctrl->value; - if (ctrl->value) - ret = ov9640_reg_rmw(client, OV9640_MVFP, + if (ctrl->val) + return ov9640_reg_rmw(client, OV9640_MVFP, OV9640_MVFP_H, 0); - else - ret = ov9640_reg_rmw(client, OV9640_MVFP, - 0, OV9640_MVFP_H); - break; + return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); } - - return ret; + return -EINVAL; } /* Get chip identification */ @@ -643,20 +596,14 @@ static int ov9640_video_probe(struct soc_camera_device *icd, */ ret = ov9640_reg_read(client, OV9640_PID, &pid); + if (!ret) + ret = ov9640_reg_read(client, OV9640_VER, &ver); + if (!ret) + ret = ov9640_reg_read(client, OV9640_MIDH, &midh); + if (!ret) + ret = ov9640_reg_read(client, OV9640_MIDL, &midl); if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_VER, &ver); - if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_MIDH, &midh); - if (ret) - goto err; - - ret = ov9640_reg_read(client, OV9640_MIDL, &midl); - if (ret) - goto err; + return ret; switch (VERSION(pid, ver)) { case OV9640_V2: @@ -670,25 +617,20 @@ static int ov9640_video_probe(struct soc_camera_device *icd, break; default: dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); - ret = -ENODEV; - goto err; + return -ENODEV; } dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", devname, pid, ver, midh, midl); -err: - return ret; + return v4l2_ctrl_handler_setup(&priv->hdl); } -static struct soc_camera_ops ov9640_ops = { - .controls = ov9640_controls, - .num_controls = ARRAY_SIZE(ov9640_controls), +static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { + .s_ctrl = ov9640_s_ctrl, }; static struct v4l2_subdev_core_ops ov9640_core_ops = { - .g_ctrl = ov9640_g_ctrl, - .s_ctrl = ov9640_s_ctrl, .g_chip_ident = ov9640_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov9640_get_register, @@ -760,12 +702,23 @@ static int ov9640_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); - icd->ops = &ov9640_ops; + v4l2_ctrl_handler_init(&priv->hdl, 2); + v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; + + kfree(priv); + return err; + } ret = ov9640_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } @@ -777,6 +730,8 @@ static int ov9640_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov9640_priv *priv = to_ov9640_sensor(sd); + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); return 0; } diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h index f8a51b70792e..6b33a972c83c 100644 --- a/drivers/media/video/ov9640.h +++ b/drivers/media/video/ov9640.h @@ -198,12 +198,10 @@ struct ov9640_reg { struct ov9640_priv { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; int model; int revision; - - bool flag_vflip; - bool flag_hflip; }; #endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ From 91b6286ff3190fece7314b61ef330da96c4d644f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 05:12:03 -0300 Subject: [PATCH 1333/1596] [media] ov772x: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov772x.c | 114 +++++++++++------------------------ 1 file changed, 36 insertions(+), 78 deletions(-) diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index f77e8995fe40..9b540421e2cb 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -401,6 +402,7 @@ struct ov772x_win_size { struct ov772x_priv { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; struct ov772x_camera_info *info; const struct ov772x_color_format *cfmt; const struct ov772x_win_size *win; @@ -518,36 +520,6 @@ static const struct ov772x_win_size ov772x_win_qvga = { .regs = ov772x_qvga_regs, }; -static const struct v4l2_queryctrl ov772x_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_BAND_STOP_FILTER, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Band-stop filter", - .minimum = 0, - .maximum = 256, - .step = 1, - .default_value = 0, - }, -}; - /* * general function */ @@ -621,52 +593,30 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - case V4L2_CID_BAND_STOP_FILTER: - ctrl->value = priv->band_filter; - break; - } - return 0; -} - -static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) { + struct ov772x_priv *priv = container_of(ctrl->handler, + struct ov772x_priv, hdl); + struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); int ret = 0; u8 val; switch (ctrl->id) { case V4L2_CID_VFLIP: - val = ctrl->value ? VFLIP_IMG : 0x00; - priv->flag_vflip = ctrl->value; + val = ctrl->val ? VFLIP_IMG : 0x00; + priv->flag_vflip = ctrl->val; if (priv->info->flags & OV772X_FLAG_VFLIP) val ^= VFLIP_IMG; - ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val); - break; + return ov772x_mask_set(client, COM3, VFLIP_IMG, val); case V4L2_CID_HFLIP: - val = ctrl->value ? HFLIP_IMG : 0x00; - priv->flag_hflip = ctrl->value; + val = ctrl->val ? HFLIP_IMG : 0x00; + priv->flag_hflip = ctrl->val; if (priv->info->flags & OV772X_FLAG_HFLIP) val ^= HFLIP_IMG; - ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val); - break; + return ov772x_mask_set(client, COM3, HFLIP_IMG, val); case V4L2_CID_BAND_STOP_FILTER: - if ((unsigned)ctrl->value > 256) - ctrl->value = 256; - if (ctrl->value == priv->band_filter) - break; - if (!ctrl->value) { + if (!ctrl->val) { /* Switch the filter off, it is on now */ ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); if (!ret) @@ -674,7 +624,7 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) BNDF_ON_OFF, 0); } else { /* Switch the filter on, set AEC low limit */ - val = 256 - ctrl->value; + val = 256 - ctrl->val; ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF); if (!ret) @@ -682,11 +632,11 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 0xff, val); } if (!ret) - priv->band_filter = ctrl->value; - break; + priv->band_filter = ctrl->val; + return ret; } - return ret; + return -EINVAL; } static int ov772x_g_chip_ident(struct v4l2_subdev *sd, @@ -1042,18 +992,14 @@ static int ov772x_video_probe(struct soc_camera_device *icd, ver, i2c_smbus_read_byte_data(client, MIDH), i2c_smbus_read_byte_data(client, MIDL)); - - return 0; + return v4l2_ctrl_handler_setup(&priv->hdl); } -static struct soc_camera_ops ov772x_ops = { - .controls = ov772x_controls, - .num_controls = ARRAY_SIZE(ov772x_controls), +static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { + .s_ctrl = ov772x_s_ctrl, }; static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { - .g_ctrl = ov772x_g_ctrl, - .s_ctrl = ov772x_s_ctrl, .g_chip_ident = ov772x_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov772x_g_register, @@ -1139,12 +1085,24 @@ static int ov772x_probe(struct i2c_client *client, priv->info = icl->priv; v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 3); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; - icd->ops = &ov772x_ops; + kfree(priv); + return err; + } ret = ov772x_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } @@ -1154,9 +1112,9 @@ static int ov772x_probe(struct i2c_client *client, static int ov772x_remove(struct i2c_client *client) { struct ov772x_priv *priv = to_ov772x(client); - struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); return 0; } From b5518a415158320d41bc31d6887d5c2aa1c9a164 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 3 Nov 2011 10:11:11 -0300 Subject: [PATCH 1334/1596] [media] V4L: sh-mobile-ceu-camera: prepare to support multi-size buffers Prepare the sh_mobile_ceu_camera friver to support the new VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF ioctl()s. The .queue_setup() vb2 operation must be able to handle buffer sizes, provided by the caller, and the .buf_prepare() operation must not use the currently configured frame format for its operation. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 124 ++++++++++++++------- 1 file changed, 81 insertions(+), 43 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 5d5781bd1447..a3153ca14089 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -90,7 +90,6 @@ struct sh_mobile_ceu_buffer { struct vb2_buffer vb; /* v4l buffer must be first */ struct list_head queue; - enum v4l2_mbus_pixelcode code; }; struct sh_mobile_ceu_dev { @@ -100,7 +99,8 @@ struct sh_mobile_ceu_dev { unsigned int irq; void __iomem *base; - unsigned long video_limit; + size_t video_limit; + size_t buf_total; spinlock_t lock; /* Protects video buffer lists */ struct list_head capture; @@ -192,6 +192,12 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) /* * Videobuf operations */ + +/* + * .queue_setup() is called to check, whether the driver can accept the + * requested number of buffers and to fill in plane sizes + * for the current frame format if required + */ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int *count, unsigned int *num_planes, @@ -200,26 +206,47 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); + int bytes_per_line; + unsigned int height; + if (fmt) { + const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, + fmt->fmt.pix.pixelformat); + if (!xlate) + return -EINVAL; + bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, + xlate->host_fmt); + height = fmt->fmt.pix.height; + } else { + /* Called from VIDIOC_REQBUFS or in compatibility mode */ + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + height = icd->user_height; + } if (bytes_per_line < 0) return bytes_per_line; - *num_planes = 1; + sizes[0] = bytes_per_line * height; - pcdev->sequence = 0; - sizes[0] = bytes_per_line * icd->user_height; alloc_ctxs[0] = pcdev->alloc_ctx; + if (!vq->num_buffers) + pcdev->sequence = 0; + if (!*count) *count = 2; - if (pcdev->video_limit) { - if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit) - *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); + /* If *num_planes != 0, we have already verified *count. */ + if (pcdev->video_limit && !*num_planes) { + size_t size = PAGE_ALIGN(sizes[0]) * *count; + + if (size + pcdev->buf_total > pcdev->video_limit) + *count = (pcdev->video_limit - pcdev->buf_total) / + PAGE_ALIGN(sizes[0]); } + *num_planes = 1; + dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); return 0; @@ -330,24 +357,41 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) } static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) +{ + struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); + + /* Added list head initialization on alloc */ + WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); + + return 0; +} + +static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) { struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct sh_mobile_ceu_buffer *buf; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); + unsigned long size; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - unsigned long size; if (bytes_per_line < 0) - return bytes_per_line; + goto error; - buf = to_ceu_vb(vb); + size = icd->user_height * bytes_per_line; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", + vb->v4l2_buf.index, vb2_plane_size(vb, 0), size); + goto error; + } + + vb2_set_plane_payload(vb, 0, size); dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - /* Added list head initialization on alloc */ - WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); - #ifdef DEBUG /* * This can be useful if you want to see if we actually fill @@ -357,31 +401,6 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); #endif - BUG_ON(NULL == icd->current_fmt); - - size = icd->user_height * bytes_per_line; - - if (vb2_plane_size(vb, 0) < size) { - dev_err(icd->parent, "Buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); - return -ENOBUFS; - } - - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); - - dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, - vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - spin_lock_irq(&pcdev->lock); list_add_tail(&buf->queue, &pcdev->capture); @@ -395,6 +414,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) sh_mobile_ceu_capture(pcdev); } spin_unlock_irq(&pcdev->lock); + + return; + +error: + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) @@ -419,11 +443,23 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) if (buf->queue.next) list_del_init(&buf->queue); + pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0)); + dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, + pcdev->buf_total); + spin_unlock_irq(&pcdev->lock); } static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) { + struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct sh_mobile_ceu_dev *pcdev = ici->priv; + + pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0)); + dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, + pcdev->buf_total); + /* This is for locking debugging only */ INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); return 0; @@ -525,6 +561,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) pm_runtime_get_sync(ici->v4l2_dev.dev); + pcdev->buf_total = 0; + ret = sh_mobile_ceu_soft_reset(pcdev); csi2_sd = find_csi2(pcdev); @@ -1712,7 +1750,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, image_mode = false; } - dev_info(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, + dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, pix->width, pix->height); dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); From 07f92448045a23d27dbc3ece3abcb6bafc618d43 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 3 Nov 2011 10:14:00 -0300 Subject: [PATCH 1335/1596] [media] V4L: mx3-camera: prepare to support multi-size buffers Prepare the mx3_camera friver to support the new VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF ioctl()s. The .queue_setup() vb2 operation must be able to handle buffer sizes, provided by the caller, and the .buf_prepare() operation must not use the currently configured frame format for its operation, which makes it superfluous for this driver. Its functionality is moved into .buf_queue(). Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx3_camera.c | 161 ++++++++++++++++--------------- 1 file changed, 85 insertions(+), 76 deletions(-) diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 24c2fe0714c5..f96f92f00f92 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -114,6 +114,7 @@ struct mx3_camera_dev { struct list_head capture; spinlock_t lock; /* Protects video buffer lists */ struct mx3_camera_buffer *active; + size_t buf_total; struct vb2_alloc_ctx *alloc_ctx; enum v4l2_field field; int sequence; @@ -198,73 +199,46 @@ static int mx3_videobuf_setup(struct vb2_queue *vq, struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - - if (bytes_per_line < 0) - return bytes_per_line; + int bytes_per_line; + unsigned int height; if (!mx3_cam->idmac_channel[0]) return -EINVAL; - *num_planes = 1; - - mx3_cam->sequence = 0; - sizes[0] = bytes_per_line * icd->user_height; - alloc_ctxs[0] = mx3_cam->alloc_ctx; - - if (!*count) - *count = 32; - - if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0]; - - return 0; -} - -static int mx3_videobuf_prepare(struct vb2_buffer *vb) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - struct scatterlist *sg; - struct mx3_camera_buffer *buf; - size_t new_size; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + if (fmt) { + const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, + fmt->fmt.pix.pixelformat); + if (!xlate) + return -EINVAL; + bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, + xlate->host_fmt); + height = fmt->fmt.pix.height; + } else { + /* Called from VIDIOC_REQBUFS or in compatibility mode */ + bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - + height = icd->user_height; + } if (bytes_per_line < 0) return bytes_per_line; - buf = to_mx3_vb(vb); - sg = &buf->sg; - - new_size = bytes_per_line * icd->user_height; - - if (vb2_plane_size(vb, 0) < new_size) { - dev_err(icd->parent, "Buffer too small (%lu < %zu)\n", - vb2_plane_size(vb, 0), new_size); - return -ENOBUFS; - } + sizes[0] = bytes_per_line * height; - if (buf->state == CSI_BUF_NEEDS_INIT) { - sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); - sg_dma_len(sg) = new_size; + alloc_ctxs[0] = mx3_cam->alloc_ctx; - buf->txd = ichan->dma_chan.device->device_prep_slave_sg( - &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT); - if (!buf->txd) - return -EIO; + if (!vq->num_buffers) + mx3_cam->sequence = 0; - buf->txd->callback_param = buf->txd; - buf->txd->callback = mx3_cam_dma_done; + if (!*count) + *count = 2; - buf->state = CSI_BUF_PREPARED; - } + /* If *num_planes != 0, we have already verified *count. */ + if (!*num_planes && + sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) + *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) / + sizes[0]; - vb2_set_plane_payload(vb, 0, new_size); + *num_planes = 1; return 0; } @@ -288,28 +262,58 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct mx3_camera_buffer *buf = to_mx3_vb(vb); - struct dma_async_tx_descriptor *txd = buf->txd; - struct idmac_channel *ichan = to_idmac_chan(txd->chan); + struct scatterlist *sg = &buf->sg; + struct dma_async_tx_descriptor *txd; + struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; struct idmac_video_param *video = &ichan->params.video; - dma_cookie_t cookie; - u32 fourcc = icd->current_fmt->host_fmt->fourcc; + const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt); unsigned long flags; + dma_cookie_t cookie; + size_t new_size; + + BUG_ON(bytes_per_line <= 0); + + new_size = bytes_per_line * icd->user_height; + + if (vb2_plane_size(vb, 0) < new_size) { + dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n", + vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size); + goto error; + } + + if (buf->state == CSI_BUF_NEEDS_INIT) { + sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); + sg_dma_len(sg) = new_size; + + txd = ichan->dma_chan.device->device_prep_slave_sg( + &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT); + if (!txd) + goto error; + + txd->callback_param = txd; + txd->callback = mx3_cam_dma_done; + + buf->state = CSI_BUF_PREPARED; + buf->txd = txd; + } else { + txd = buf->txd; + } + + vb2_set_plane_payload(vb, 0, new_size); /* This is the configuration of one sg-element */ - video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); + video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc); if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { /* - * If the IPU DMA channel is configured to transport - * generic 8-bit data, we have to set up correctly the - * geometry parameters upon the current pixel format. - * So, since the DMA horizontal parameters are expressed - * in bytes not pixels, convert these in the right unit. + * If the IPU DMA channel is configured to transfer generic + * 8-bit data, we have to set up the geometry parameters + * correctly, according to the current pixel format. The DMA + * horizontal parameters in this case are expressed in bytes, + * not in pixels. */ - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - BUG_ON(bytes_per_line <= 0); - video->out_width = bytes_per_line; video->out_height = icd->user_height; video->out_stride = bytes_per_line; @@ -353,6 +357,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) mx3_cam->active = NULL; spin_unlock_irqrestore(&mx3_cam->lock, flags); +error: vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } @@ -386,17 +391,24 @@ static void mx3_videobuf_release(struct vb2_buffer *vb) } spin_unlock_irqrestore(&mx3_cam->lock, flags); + + mx3_cam->buf_total -= vb2_plane_size(vb, 0); } static int mx3_videobuf_init(struct vb2_buffer *vb) { + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct mx3_camera_dev *mx3_cam = ici->priv; struct mx3_camera_buffer *buf = to_mx3_vb(vb); + /* This is for locking debugging only */ INIT_LIST_HEAD(&buf->queue); sg_init_table(&buf->sg, 1); buf->state = CSI_BUF_NEEDS_INIT; - buf->txd = NULL; + + mx3_cam->buf_total += vb2_plane_size(vb, 0); return 0; } @@ -407,13 +419,12 @@ static int mx3_stop_streaming(struct vb2_queue *q) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - struct dma_chan *chan; struct mx3_camera_buffer *buf, *tmp; unsigned long flags; if (ichan) { - chan = &ichan->dma_chan; - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + struct dma_chan *chan = &ichan->dma_chan; + chan->device->device_control(chan, DMA_PAUSE, 0); } spin_lock_irqsave(&mx3_cam->lock, flags); @@ -421,8 +432,8 @@ static int mx3_stop_streaming(struct vb2_queue *q) mx3_cam->active = NULL; list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { - buf->state = CSI_BUF_NEEDS_INIT; list_del_init(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } spin_unlock_irqrestore(&mx3_cam->lock, flags); @@ -432,7 +443,6 @@ static int mx3_stop_streaming(struct vb2_queue *q) static struct vb2_ops mx3_videobuf_ops = { .queue_setup = mx3_videobuf_setup, - .buf_prepare = mx3_videobuf_prepare, .buf_queue = mx3_videobuf_queue, .buf_cleanup = mx3_videobuf_release, .buf_init = mx3_videobuf_init, @@ -516,6 +526,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd) mx3_camera_activate(mx3_cam, icd); + mx3_cam->buf_total = 0; mx3_cam->icd = icd; dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", @@ -1263,8 +1274,6 @@ static int __devexit mx3_camera_remove(struct platform_device *pdev) dmaengine_put(); - dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n"); - return 0; } From 7ae77ee92fea7c115324096372a2a125d8bc26d7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 28 Sep 2011 09:25:28 -0300 Subject: [PATCH 1336/1596] [media] V4L: soc-camera: add 2 new ioctl() handlers This patch adds two new ioctl() handlers: .vidioc_create_bufs() and .vidioc_prepare_buf() for compliant vb2 soc-camera hosts. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 33 ++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index b56f4b78273d..8d5c421a803c 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -318,6 +318,32 @@ static int soc_camera_dqbuf(struct file *file, void *priv, return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); } +static int soc_camera_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *create) +{ + struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + + /* videobuf2 only */ + if (ici->ops->init_videobuf) + return -EINVAL; + else + return vb2_create_bufs(&icd->vb2_vidq, create); +} + +static int soc_camera_prepare_buf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + + /* videobuf2 only */ + if (ici->ops->init_videobuf) + return -EINVAL; + else + return vb2_prepare_buf(&icd->vb2_vidq, b); +} + /* Always entered with .video_lock held */ static int soc_camera_init_user_formats(struct soc_camera_device *icd) { @@ -1041,6 +1067,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (!control || !control->driver || !dev_get_drvdata(control) || !try_module_get(control->driver->owner)) { icl->del_device(icd); + ret = -ENODEV; goto enodrv; } } @@ -1312,19 +1339,21 @@ static int soc_camera_device_register(struct soc_camera_device *icd) static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_querycap = soc_camera_querycap, + .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, .vidioc_enum_input = soc_camera_enum_input, .vidioc_g_input = soc_camera_g_input, .vidioc_s_input = soc_camera_s_input, .vidioc_s_std = soc_camera_s_std, .vidioc_enum_framesizes = soc_camera_enum_fsizes, .vidioc_reqbufs = soc_camera_reqbufs, - .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, .vidioc_querybuf = soc_camera_querybuf, .vidioc_qbuf = soc_camera_qbuf, .vidioc_dqbuf = soc_camera_dqbuf, + .vidioc_create_bufs = soc_camera_create_bufs, + .vidioc_prepare_buf = soc_camera_prepare_buf, .vidioc_streamon = soc_camera_streamon, .vidioc_streamoff = soc_camera_streamoff, .vidioc_cropcap = soc_camera_cropcap, From 489759c0ca26bcd405c82966bdce7ff7fec5a110 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 7 Sep 2011 11:59:47 -0300 Subject: [PATCH 1337/1596] [media] V4L: sh_mobile_ceu_camera: the host shall configure the pipeline It is a task of the host / bridge driver to bind single subdevices into a pipeline, not of respective subdevices. Eventually this might be handled by the Media Controller API. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index a3153ca14089..f390682629cf 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -566,16 +566,24 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) ret = sh_mobile_ceu_soft_reset(pcdev); csi2_sd = find_csi2(pcdev); + if (csi2_sd) + csi2_sd->grp_id = (long)icd; ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); - if (ret != -ENODEV && ret != -ENOIOCTLCMD && ret < 0) { + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { pm_runtime_put_sync(ici->v4l2_dev.dev); - } else { - pcdev->icd = icd; - ret = 0; + return ret; } - return ret; + /* + * -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver + * has not found this soc-camera device among its clients + */ + if (ret == -ENODEV && csi2_sd) + csi2_sd->grp_id = 0; + pcdev->icd = icd; + + return 0; } /* Called with .video_lock held */ @@ -588,6 +596,8 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) BUG_ON(icd != pcdev->icd); v4l2_subdev_call(csi2_sd, core, s_power, 0); + if (csi2_sd) + csi2_sd->grp_id = 0; /* disable capture, disable interrupts */ ceu_write(pcdev, CEIER, 0); sh_mobile_ceu_soft_reset(pcdev); From da83d9dc0ac18ffb07b5b344e237005a0ba08089 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 5 Sep 2011 08:26:20 -0300 Subject: [PATCH 1338/1596] [media] V4L: sh_mobile_csi2: do not guess the client, the host tells us We do not have to scan the list of subdevices to find our client - the sensor, the host has already set our grp_id value. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_csi2.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 6f9f2b7ee453..91c680a72849 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -201,22 +201,13 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) static int sh_csi2_client_connect(struct sh_csi2 *priv) { struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; - struct v4l2_subdev *sd, *csi2_sd = &priv->subdev; - struct soc_camera_device *icd = NULL; + struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; + struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); struct device *dev = v4l2_get_subdevdata(&priv->subdev); struct v4l2_mbus_config cfg; unsigned long common_flags, csi2_flags; int i, ret; - v4l2_device_for_each_subdev(sd, csi2_sd->v4l2_dev) - if (sd->grp_id) { - icd = (struct soc_camera_device *)sd->grp_id; - break; - } - - if (!icd) - return -EINVAL; - for (i = 0; i < pdata->num_clients; i++) if (&pdata->clients[i].pdev->dev == icd->pdev) break; @@ -246,7 +237,7 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) } cfg.type = V4L2_MBUS_CSI2; - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); + ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg); if (ret == -ENOIOCTLCMD) common_flags = csi2_flags; else if (!ret) @@ -262,8 +253,6 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) priv->mipi_flags = common_flags; priv->client = pdata->clients + i; - csi2_sd->grp_id = (long)icd; - pm_runtime_get_sync(dev); sh_csi2_hwinit(priv); @@ -274,7 +263,6 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) static void sh_csi2_client_disconnect(struct sh_csi2 *priv) { priv->client = NULL; - priv->subdev.grp_id = 0; pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); } From 3dcc731a93679d75a1f90a969b34aa9d7acd1cbf Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 5 Sep 2011 12:33:21 -0300 Subject: [PATCH 1339/1596] [media] V4L: soc-camera: split a function into two The soc_camera_power_set() function processes two cases: power on anf off. These two cases don't share and common code, and the function is always called with a constant power on / off argument. Splitting this function into two removes a condition check, reduces indentation levels and makes the code look cleaner. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 65 +++++++++++++++++--------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 8d5c421a803c..d3eeb08be321 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -50,49 +50,52 @@ static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ -static int soc_camera_power_set(struct soc_camera_device *icd, - struct soc_camera_link *icl, - int power_on) +static int soc_camera_power_on(struct soc_camera_device *icd, + struct soc_camera_link *icl) { int ret; - if (power_on) { - ret = regulator_bulk_enable(icl->num_regulators, - icl->regulators); - if (ret < 0) { - dev_err(icd->pdev, "Cannot enable regulators\n"); - return ret; - } + ret = regulator_bulk_enable(icl->num_regulators, + icl->regulators); + if (ret < 0) { + dev_err(icd->pdev, "Cannot enable regulators\n"); + return ret; + } - if (icl->power) - ret = icl->power(icd->pdev, power_on); + if (icl->power) { + ret = icl->power(icd->pdev, 1); if (ret < 0) { dev_err(icd->pdev, "Platform failed to power-on the camera.\n"); regulator_bulk_disable(icl->num_regulators, icl->regulators); - return ret; } - } else { - ret = 0; - if (icl->power) - ret = icl->power(icd->pdev, 0); + } + + return ret; +} + +static int soc_camera_power_off(struct soc_camera_device *icd, + struct soc_camera_link *icl) +{ + int ret; + + if (icl->power) { + ret = icl->power(icd->pdev, 0); if (ret < 0) { dev_err(icd->pdev, "Platform failed to power-off the camera.\n"); return ret; } - - ret = regulator_bulk_disable(icl->num_regulators, - icl->regulators); - if (ret < 0) { - dev_err(icd->pdev, "Cannot disable regulators\n"); - return ret; - } } - return 0; + ret = regulator_bulk_disable(icl->num_regulators, + icl->regulators); + if (ret < 0) + dev_err(icd->pdev, "Cannot disable regulators\n"); + + return ret; } const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( @@ -502,7 +505,7 @@ static int soc_camera_open(struct file *file) }, }; - ret = soc_camera_power_set(icd, icl, 1); + ret = soc_camera_power_on(icd, icl); if (ret < 0) goto epower; @@ -556,7 +559,7 @@ static int soc_camera_open(struct file *file) eresume: ici->ops->remove(icd); eiciadd: - soc_camera_power_set(icd, icl, 0); + soc_camera_power_off(icd, icl); epower: icd->use_count--; module_put(ici->ops->owner); @@ -580,7 +583,7 @@ static int soc_camera_close(struct file *file) if (ici->ops->init_videobuf2) vb2_queue_release(&icd->vb2_vidq); - soc_camera_power_set(icd, icl, 0); + soc_camera_power_off(icd, icl); } if (icd->streamer == file) @@ -1026,7 +1029,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (ret < 0) goto ereg; - ret = soc_camera_power_set(icd, icl, 1); + ret = soc_camera_power_on(icd, icl); if (ret < 0) goto epower; @@ -1106,7 +1109,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) ici->ops->remove(icd); - soc_camera_power_set(icd, icl, 0); + soc_camera_power_off(icd, icl); mutex_unlock(&icd->video_lock); @@ -1129,7 +1132,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) evdc: ici->ops->remove(icd); eadd: - soc_camera_power_set(icd, icl, 0); + soc_camera_power_off(icd, icl); epower: regulator_bulk_free(icl->num_regulators, icl->regulators); ereg: From fff96b6685d6fec14deaacbce9e27fbb8feed53d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 5 Sep 2011 13:50:27 -0300 Subject: [PATCH 1340/1596] [media] V4L: soc_camera_platform: do not leave dangling invalid pointers The life-time of soc-camera device objects can be longer, than the time, it is attached to a client driver, therefore all references to the driver own data have to be cleared, when the driver is detached. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera_platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index f5ebe59a5555..c8f6b188496d 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -173,7 +173,9 @@ static int soc_camera_platform_probe(struct platform_device *pdev) static int soc_camera_platform_remove(struct platform_device *pdev) { struct soc_camera_platform_priv *priv = get_priv(pdev); + struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev); + p->icd->control = NULL; v4l2_device_unregister_subdev(&priv->subdev); platform_set_drvdata(pdev, NULL); kfree(priv); From 7b9d8c3c4cfa0dc21f630c17c5f20e524dab487c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 8 Sep 2011 04:36:06 -0300 Subject: [PATCH 1341/1596] [media] V4L: soc-camera: call subdevice .s_power() method, when powering up or down Currently soc-camera can use power regulators and platform specific methods to power clients up and down. Additionally, client drivers can provide their own subdevice .s_power() methods, acting directly on the device. This patch adds calls to this method, when external power supplies are on. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 42 ++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index d3eeb08be321..9a62ed08d86a 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -53,10 +53,9 @@ static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ static int soc_camera_power_on(struct soc_camera_device *icd, struct soc_camera_link *icl) { - int ret; - - ret = regulator_bulk_enable(icl->num_regulators, - icl->regulators); + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int ret = regulator_bulk_enable(icl->num_regulators, + icl->regulators); if (ret < 0) { dev_err(icd->pdev, "Cannot enable regulators\n"); return ret; @@ -67,19 +66,33 @@ static int soc_camera_power_on(struct soc_camera_device *icd, if (ret < 0) { dev_err(icd->pdev, "Platform failed to power-on the camera.\n"); - - regulator_bulk_disable(icl->num_regulators, - icl->regulators); + goto elinkpwr; } } + ret = v4l2_subdev_call(sd, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + goto esdpwr; + + return 0; + +esdpwr: + if (icl->power) + icl->power(icd->pdev, 0); +elinkpwr: + regulator_bulk_disable(icl->num_regulators, + icl->regulators); return ret; } static int soc_camera_power_off(struct soc_camera_device *icd, struct soc_camera_link *icl) { - int ret; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + int ret = v4l2_subdev_call(sd, core, s_power, 0); + + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; if (icl->power) { ret = icl->power(icd->pdev, 0); @@ -1029,6 +1042,12 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (ret < 0) goto ereg; + /* + * This will not yet call v4l2_subdev_core_ops::s_power(1), because the + * subdevice has not been initialised yet. We'll have to call it once + * again after initialisation, even though it shouldn't be needed, we + * don't do any IO here. + */ ret = soc_camera_power_on(icd, icl); if (ret < 0) goto epower; @@ -1099,6 +1118,10 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (ret < 0) goto evidstart; + ret = v4l2_subdev_call(sd, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + goto esdpwr; + /* Try to improve our guess of a reasonable window format */ if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { icd->user_width = mf.width; @@ -1115,6 +1138,8 @@ static int soc_camera_probe(struct soc_camera_device *icd) return 0; +esdpwr: + video_unregister_device(icd->vdev); evidstart: mutex_unlock(&icd->video_lock); soc_camera_free_user_formats(icd); @@ -1129,6 +1154,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) enodrv: eadddev: video_device_release(icd->vdev); + icd->vdev = NULL; evdc: ici->ops->remove(icd); eadd: From 25e965ad2727527216724142d1fbeeb0e9dcf7a8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 05:20:33 -0300 Subject: [PATCH 1342/1596] [media] rj54n1cb0c: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/rj54n1cb0c.c | 141 +++++++++---------------------- 1 file changed, 38 insertions(+), 103 deletions(-) diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index c30221104c6f..9a871537d233 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -18,6 +18,7 @@ #include #include #include +#include #define RJ54N1_DEV_CODE 0x0400 #define RJ54N1_DEV_CODE2 0x0401 @@ -148,6 +149,7 @@ struct rj54n1_clock_div { struct rj54n1 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; struct rj54n1_clock_div clk_div; const struct rj54n1_datafmt *fmt; struct v4l2_rect rect; /* Sensor window */ @@ -1177,132 +1179,51 @@ static int rj54n1_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl rj54n1_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 66, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, -}; - -static struct soc_camera_ops rj54n1_ops = { - .controls = rj54n1_controls, - .num_controls = ARRAY_SIZE(rj54n1_controls), -}; - -static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) { + struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl); + struct v4l2_subdev *sd = &rj54n1->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); - if (data < 0) - return -EIO; - ctrl->value = !(data & 1); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); - if (data < 0) - return -EIO; - ctrl->value = !(data & 2); - break; - case V4L2_CID_GAIN: - data = reg_read(client, RJ54N1_Y_GAIN); - if (data < 0) - return -EIO; - - ctrl->value = data / 2; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = rj54n1->auto_wb; - break; - } - - return 0; -} - -static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - int data; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct v4l2_queryctrl *qctrl; - - qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); - if (!qctrl) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1); else data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_HFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2); else data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_GAIN: - if (ctrl->value > qctrl->maximum || - ctrl->value < qctrl->minimum) - return -EINVAL; - else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) + if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0) return -EIO; - break; + return 0; case V4L2_CID_AUTO_WHITE_BALANCE: /* Auto WB area - whole image */ - if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->value << 7, + if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7, 0x80) < 0) return -EIO; - rj54n1->auto_wb = ctrl->value; - break; + rj54n1->auto_wb = ctrl->val; + return 0; } - return 0; + return -EINVAL; } +static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = { + .s_ctrl = rj54n1_s_ctrl, +}; + static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { - .g_ctrl = rj54n1_g_ctrl, - .s_ctrl = rj54n1_s_ctrl, .g_chip_ident = rj54n1_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = rj54n1_g_register, @@ -1432,8 +1353,22 @@ static int rj54n1_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops); + v4l2_ctrl_handler_init(&rj54n1->hdl, 4); + v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 66); + v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + rj54n1->subdev.ctrl_handler = &rj54n1->hdl; + if (rj54n1->hdl.error) { + int err = rj54n1->hdl.error; - icd->ops = &rj54n1_ops; + kfree(rj54n1); + return err; + } rj54n1->clk_div = clk_div; rj54n1->rect.left = RJ54N1_COLUMN_SKIP; @@ -1449,12 +1384,11 @@ static int rj54n1_probe(struct i2c_client *client, ret = rj54n1_video_probe(icd, client, rj54n1_priv); if (ret < 0) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&rj54n1->hdl); kfree(rj54n1); return ret; } - - return ret; + return v4l2_ctrl_handler_setup(&rj54n1->hdl); } static int rj54n1_remove(struct i2c_client *client) @@ -1463,9 +1397,10 @@ static int rj54n1_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; struct soc_camera_link *icl = to_soc_camera_link(icd); - icd->ops = NULL; + v4l2_device_unregister_subdev(&rj54n1->subdev); if (icl->free_bus) icl->free_bus(icl); + v4l2_ctrl_handler_free(&rj54n1->hdl); kfree(rj54n1); return 0; From ab7b50ae406ee918ba68a13133a9cdf89c70fe4f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 05:22:39 -0300 Subject: [PATCH 1343/1596] [media] mt9v022: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v022.c | 265 ++++++++++++++-------------------- 1 file changed, 107 insertions(+), 158 deletions(-) diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 53149a73874b..7e2aeda21752 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -18,6 +18,7 @@ #include #include #include +#include /* * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c @@ -101,6 +102,17 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { struct mt9v022 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/auto-exposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; + struct { + /* gain/auto-gain cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; struct v4l2_rect rect; /* Sensor window */ const struct mt9v022_datafmt *fmt; const struct mt9v022_datafmt *fmts; @@ -179,6 +191,8 @@ static int mt9v022_init(struct i2c_client *client) ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); if (!ret) ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); + if (!ret) + return v4l2_ctrl_handler_setup(&mt9v022->hdl); return ret; } @@ -431,215 +445,117 @@ static int mt9v022_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl mt9v022_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Analog Gain", - .minimum = 64, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9v022_ops = { - .controls = mt9v022_controls, - .num_controls = ARRAY_SIZE(mt9v022_controls), -}; - -static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { + struct mt9v022 *mt9v022 = container_of(ctrl->handler, + struct mt9v022, hdl); + struct v4l2_subdev *sd = &mt9v022->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct v4l2_queryctrl *qctrl; + struct v4l2_ctrl *gain = mt9v022->gain; + struct v4l2_ctrl *exp = mt9v022->exposure; unsigned long range; int data; - qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); - switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9V022_READ_MODE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x10); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, MT9V022_READ_MODE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x20); - break; - case V4L2_CID_EXPOSURE_AUTO: - data = reg_read(client, MT9V022_AEC_AGC_ENABLE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x1); - break; case V4L2_CID_AUTOGAIN: - data = reg_read(client, MT9V022_AEC_AGC_ENABLE); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x2); - break; - case V4L2_CID_GAIN: data = reg_read(client, MT9V022_ANALOG_GAIN); if (data < 0) return -EIO; - range = qctrl->maximum - qctrl->minimum; - ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; - - break; - case V4L2_CID_EXPOSURE: + range = gain->maximum - gain->minimum; + gain->val = ((data - 16) * range + 24) / 48 + gain->minimum; + return 0; + case V4L2_CID_EXPOSURE_AUTO: data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); if (data < 0) return -EIO; - range = qctrl->maximum - qctrl->minimum; - ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; - - break; + range = exp->maximum - exp->minimum; + exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; + return 0; } - return 0; + return -EINVAL; } -static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) { - int data; + struct mt9v022 *mt9v022 = container_of(ctrl->handler, + struct mt9v022, hdl); + struct v4l2_subdev *sd = &mt9v022->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct v4l2_queryctrl *qctrl; - - qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); - if (!qctrl) - return -EINVAL; + int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9V022_READ_MODE, 0x10); else data = reg_clear(client, MT9V022_READ_MODE, 0x10); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_HFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9V022_READ_MODE, 0x20); else data = reg_clear(client, MT9V022_READ_MODE, 0x20); if (data < 0) return -EIO; - break; - case V4L2_CID_GAIN: - /* mt9v022 has minimum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; + return 0; + case V4L2_CID_AUTOGAIN: + if (ctrl->val) { + if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) + return -EIO; + } else { + struct v4l2_ctrl *gain = mt9v022->gain; + /* mt9v022 has minimum == default */ + unsigned long range = gain->maximum - gain->minimum; /* Valid values 16 to 64, 32 to 64 must be even. */ - unsigned long gain = ((ctrl->value - qctrl->minimum) * + unsigned long gain_val = ((gain->val - gain->minimum) * 48 + range / 2) / range + 16; - if (gain >= 32) - gain &= ~1; + + if (gain_val >= 32) + gain_val &= ~1; + /* * The user wants to set gain manually, hope, she * knows, what she's doing... Switch AGC off. */ - if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) return -EIO; dev_dbg(&client->dev, "Setting gain from %d to %lu\n", - reg_read(client, MT9V022_ANALOG_GAIN), gain); - if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) + reg_read(client, MT9V022_ANALOG_GAIN), gain_val); + if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0) return -EIO; } - break; - case V4L2_CID_EXPOSURE: - /* mt9v022 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; - unsigned long shutter = ((ctrl->value - qctrl->minimum) * - 479 + range / 2) / range + 1; + return 0; + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_AUTO) { + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); + } else { + struct v4l2_ctrl *exp = mt9v022->exposure; + unsigned long range = exp->maximum - exp->minimum; + unsigned long shutter = ((exp->val - exp->minimum) * + 479 + range / 2) / range + 1; + /* * The user wants to set shutter width manually, hope, * she knows, what she's doing... Switch AEC off. */ - - if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); + if (data < 0) return -EIO; - dev_dbg(&client->dev, "Shutter width from %d to %lu\n", - reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), - shutter); + reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), + shutter); if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, - shutter) < 0) + shutter) < 0) return -EIO; } - break; - case V4L2_CID_AUTOGAIN: - if (ctrl->value) - data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); - else - data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); - if (data < 0) - return -EIO; - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) - data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); - else - data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); - if (data < 0) - return -EIO; - break; + return 0; } - return 0; + return -EINVAL; } /* @@ -752,9 +668,12 @@ static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) return 0; } +static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { + .g_volatile_ctrl = mt9v022_g_volatile_ctrl, + .s_ctrl = mt9v022_s_ctrl, +}; + static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { - .g_ctrl = mt9v022_g_ctrl, - .s_ctrl = mt9v022_s_ctrl, .g_chip_ident = mt9v022_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9v022_g_register, @@ -906,10 +825,39 @@ static int mt9v022_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); + v4l2_ctrl_handler_init(&mt9v022->hdl, 6); + v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 64); + + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl, + &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 255, 1, 255); + + mt9v022->subdev.ctrl_handler = &mt9v022->hdl; + if (mt9v022->hdl.error) { + int err = mt9v022->hdl.error; + + kfree(mt9v022); + return err; + } + v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, + V4L2_EXPOSURE_MANUAL, true); + v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true); mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; - icd->ops = &mt9v022_ops; /* * MT9V022 _really_ corrupts the first read out line. * TODO: verify on i.MX31 @@ -922,7 +870,7 @@ static int mt9v022_probe(struct i2c_client *client, ret = mt9v022_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&mt9v022->hdl); kfree(mt9v022); } @@ -934,8 +882,9 @@ static int mt9v022_remove(struct i2c_client *client) struct mt9v022 *mt9v022 = to_mt9v022(client); struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&mt9v022->subdev); mt9v022_video_remove(icd); + v4l2_ctrl_handler_free(&mt9v022->hdl); kfree(mt9v022); return 0; From f026671d2bbbe8b25906bd266a1164a73fdeaa7f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 05:43:05 -0300 Subject: [PATCH 1344/1596] [media] ov2640: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov2640.c | 90 +++++++++++------------------------- 1 file changed, 27 insertions(+), 63 deletions(-) diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 2826aff5ea27..981767f2d8ea 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -24,6 +24,7 @@ #include #include #include +#include #define VAL_SET(x, mask, rshift, lshift) \ ((((x) >> rshift) & mask) << lshift) @@ -300,11 +301,10 @@ struct ov2640_win_size { struct ov2640_priv { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; enum v4l2_mbus_pixelcode cfmt_code; const struct ov2640_win_size *win; int model; - u16 flag_vflip:1; - u16 flag_hflip:1; }; /* @@ -609,29 +609,6 @@ static enum v4l2_mbus_pixelcode ov2640_codes[] = { V4L2_MBUS_FMT_RGB565_2X8_LE, }; -/* - * Supported controls - */ -static const struct v4l2_queryctrl ov2640_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - /* * General functions */ @@ -701,43 +678,23 @@ static int ov2640_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2640_priv *priv = to_ov2640(client); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - } - return 0; -} - -static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) { + struct v4l2_subdev *sd = + &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2640_priv *priv = to_ov2640(client); - int ret = 0; u8 val; switch (ctrl->id) { case V4L2_CID_VFLIP: - val = ctrl->value ? REG04_VFLIP_IMG : 0x00; - priv->flag_vflip = ctrl->value ? 1 : 0; - ret = ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); - break; + val = ctrl->val ? REG04_VFLIP_IMG : 0x00; + return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); case V4L2_CID_HFLIP: - val = ctrl->value ? REG04_HFLIP_IMG : 0x00; - priv->flag_hflip = ctrl->value ? 1 : 0; - ret = ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); - break; + val = ctrl->val ? REG04_HFLIP_IMG : 0x00; + return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); } - return ret; + return -EINVAL; } static int ov2640_g_chip_ident(struct v4l2_subdev *sd, @@ -1022,20 +979,17 @@ static int ov2640_video_probe(struct soc_camera_device *icd, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", devname, pid, ver, midh, midl); - return 0; + return v4l2_ctrl_handler_setup(&priv->hdl); err: return ret; } -static struct soc_camera_ops ov2640_ops = { - .controls = ov2640_controls, - .num_controls = ARRAY_SIZE(ov2640_controls), +static const struct v4l2_ctrl_ops ov2640_ctrl_ops = { + .s_ctrl = ov2640_s_ctrl, }; static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { - .g_ctrl = ov2640_g_ctrl, - .s_ctrl = ov2640_s_ctrl, .g_chip_ident = ov2640_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov2640_g_register, @@ -1113,12 +1067,22 @@ static int ov2640_probe(struct i2c_client *client, } v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 2); + v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; - icd->ops = &ov2640_ops; + kfree(priv); + return err; + } ret = ov2640_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } else { dev_info(&adapter->dev, "OV2640 Probed\n"); @@ -1130,9 +1094,9 @@ static int ov2640_probe(struct i2c_client *client, static int ov2640_remove(struct i2c_client *client) { struct ov2640_priv *priv = to_ov2640(client); - struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); return 0; } From afd9690c72c3acf77b7f8731b2fcafafd3b7e29e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 12 Sep 2011 09:52:01 -0300 Subject: [PATCH 1345/1596] [media] ov6650: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] [jkrzyszt@tis.icnet.pl: fix a typo in the register name] Acked-by: Janusz Krzysztofik Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov6650.c | 381 +++++++++++------------------------ 1 file changed, 115 insertions(+), 266 deletions(-) diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 654b2f591ae2..efa45132c992 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -32,6 +32,7 @@ #include #include #include +#include /* Register definitions */ #define REG_GAIN 0x00 /* range 00 - 3F */ @@ -177,20 +178,23 @@ struct ov6650_reg { struct ov6650 { struct v4l2_subdev subdev; - - int gain; - int blue; - int red; - int saturation; - int hue; - int brightness; - int exposure; - int gamma; - int aec; - bool vflip; - bool hflip; - bool awb; - bool agc; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/autoexposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; + struct { + /* gain/autogain cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; + struct { + /* blue/red/autowhitebalance cluster */ + struct v4l2_ctrl *autowb; + struct v4l2_ctrl *blue; + struct v4l2_ctrl *red; + }; bool half_scale; /* scale down output by 2 */ struct v4l2_rect rect; /* sensor cropping window */ unsigned long pclk_limit; /* from host */ @@ -210,126 +214,6 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = { V4L2_MBUS_FMT_Y8_1X8, }; -static const struct v4l2_queryctrl ov6650_controls[] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "AGC", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = DEF_GAIN, - }, - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "AWB", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_BLUE, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_RED, - }, - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 0xf, - .step = 1, - .default_value = 0x8, - }, - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = HUE_MASK, - .step = 1, - .default_value = DEF_HUE, - }, - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x80, - }, - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "AEC", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = DEF_AECH, - }, - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x12, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - /* read a register */ static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) { @@ -420,166 +304,91 @@ static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) } /* Get status of additional camera capabilities */ -static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { + struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); + struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - uint8_t reg; + uint8_t reg, reg2; int ret = 0; switch (ctrl->id) { case V4L2_CID_AUTOGAIN: - ctrl->value = priv->agc; - break; - case V4L2_CID_GAIN: - if (priv->agc) { - ret = ov6650_reg_read(client, REG_GAIN, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->gain; - } - break; + ret = ov6650_reg_read(client, REG_GAIN, ®); + if (!ret) + priv->gain->val = reg; + return ret; case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = priv->awb; - break; - case V4L2_CID_BLUE_BALANCE: - if (priv->awb) { - ret = ov6650_reg_read(client, REG_BLUE, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->blue; - } - break; - case V4L2_CID_RED_BALANCE: - if (priv->awb) { - ret = ov6650_reg_read(client, REG_RED, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->red; + ret = ov6650_reg_read(client, REG_BLUE, ®); + if (!ret) + ret = ov6650_reg_read(client, REG_RED, ®2); + if (!ret) { + priv->blue->val = reg; + priv->red->val = reg2; } - break; - case V4L2_CID_SATURATION: - ctrl->value = priv->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = priv->hue; - break; - case V4L2_CID_BRIGHTNESS: - ctrl->value = priv->brightness; - break; + return ret; case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = priv->aec; - break; - case V4L2_CID_EXPOSURE: - if (priv->aec) { - ret = ov6650_reg_read(client, REG_AECH, ®); - ctrl->value = reg; - } else { - ctrl->value = priv->exposure; - } - break; - case V4L2_CID_GAMMA: - ctrl->value = priv->gamma; - break; - case V4L2_CID_VFLIP: - ctrl->value = priv->vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->hflip; - break; + ret = ov6650_reg_read(client, REG_AECH, ®); + if (!ret) + priv->exposure->val = reg; + return ret; } - return ret; + return -EINVAL; } /* Set status of additional camera capabilities */ -static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) { + struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); + struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); int ret = 0; switch (ctrl->id) { case V4L2_CID_AUTOGAIN: ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_AGC : 0, COMB_AGC); - if (!ret) - priv->agc = ctrl->value; - break; - case V4L2_CID_GAIN: - ret = ov6650_reg_write(client, REG_GAIN, ctrl->value); - if (!ret) - priv->gain = ctrl->value; - break; + ctrl->val ? COMB_AGC : 0, COMB_AGC); + if (!ret && !ctrl->val) + ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val); + return ret; case V4L2_CID_AUTO_WHITE_BALANCE: ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_AWB : 0, COMB_AWB); - if (!ret) - priv->awb = ctrl->value; - break; - case V4L2_CID_BLUE_BALANCE: - ret = ov6650_reg_write(client, REG_BLUE, ctrl->value); - if (!ret) - priv->blue = ctrl->value; - break; - case V4L2_CID_RED_BALANCE: - ret = ov6650_reg_write(client, REG_RED, ctrl->value); - if (!ret) - priv->red = ctrl->value; - break; + ctrl->val ? COMB_AWB : 0, COMB_AWB); + if (!ret && !ctrl->val) { + ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val); + if (!ret) + ret = ov6650_reg_write(client, REG_RED, + priv->red->val); + } + return ret; case V4L2_CID_SATURATION: - ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value), + return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val), SAT_MASK); - if (!ret) - priv->saturation = ctrl->value; - break; case V4L2_CID_HUE: - ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value), + return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val), HUE_MASK); - if (!ret) - priv->hue = ctrl->value; - break; case V4L2_CID_BRIGHTNESS: - ret = ov6650_reg_write(client, REG_BRT, ctrl->value); - if (!ret) - priv->brightness = ctrl->value; - break; + return ov6650_reg_write(client, REG_BRT, ctrl->val); case V4L2_CID_EXPOSURE_AUTO: - switch (ctrl->value) { - case V4L2_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_AUTO) ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); - break; - default: + else ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); - break; - } - if (!ret) - priv->aec = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - ret = ov6650_reg_write(client, REG_AECH, ctrl->value); - if (!ret) - priv->exposure = ctrl->value; - break; + if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) + ret = ov6650_reg_write(client, REG_AECH, + priv->exposure->val); + return ret; case V4L2_CID_GAMMA: - ret = ov6650_reg_write(client, REG_GAM1, ctrl->value); - if (!ret) - priv->gamma = ctrl->value; - break; + return ov6650_reg_write(client, REG_GAM1, ctrl->val); case V4L2_CID_VFLIP: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V); - if (!ret) - priv->vflip = ctrl->value; - break; + return ov6650_reg_rmw(client, REG_COMB, + ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V); case V4L2_CID_HFLIP: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H); - if (!ret) - priv->hflip = ctrl->value; - break; + return ov6650_reg_rmw(client, REG_COMB, + ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H); } - return ret; + return -EINVAL; } /* Get chip identification */ @@ -1048,14 +857,12 @@ static int ov6650_video_probe(struct soc_camera_device *icd, return ret; } -static struct soc_camera_ops ov6650_ops = { - .controls = ov6650_controls, - .num_controls = ARRAY_SIZE(ov6650_controls), +static const struct v4l2_ctrl_ops ov6550_ctrl_ops = { + .g_volatile_ctrl = ov6550_g_volatile_ctrl, + .s_ctrl = ov6550_s_ctrl, }; static struct v4l2_subdev_core_ops ov6650_core_ops = { - .g_ctrl = ov6650_g_ctrl, - .s_ctrl = ov6650_s_ctrl, .g_chip_ident = ov6650_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov6650_get_register, @@ -1164,8 +971,46 @@ static int ov6650_probe(struct i2c_client *client, } v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 13); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN); + priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE); + priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_SATURATION, 0, 0xf, 1, 0x8); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); + priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, + &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); + v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, + V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); + + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; - icd->ops = &ov6650_ops; + kfree(priv); + return err; + } + v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); + v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); + v4l2_ctrl_auto_cluster(2, &priv->autoexposure, + V4L2_EXPOSURE_MANUAL, true); priv->rect.left = DEF_HSTRT << 1; priv->rect.top = DEF_VSTRT << 1; @@ -1176,9 +1021,11 @@ static int ov6650_probe(struct i2c_client *client, priv->colorspace = V4L2_COLORSPACE_JPEG; ret = ov6650_video_probe(icd, client); + if (!ret) + ret = v4l2_ctrl_handler_setup(&priv->hdl); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } @@ -1189,6 +1036,8 @@ static int ov6650_remove(struct i2c_client *client) { struct ov6650 *priv = to_ov6650(client); + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); return 0; } From 34e181c5211f106f1d464e9bcb50bb88398126e2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 06:03:11 -0300 Subject: [PATCH 1346/1596] [media] ov9740: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov9740.c | 83 ++++++++++++------------------------ 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index 5920f600990f..3dd910dcc5b8 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c @@ -18,6 +18,7 @@ #include #include #include +#include #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) @@ -194,6 +195,7 @@ struct ov9740_reg { struct ov9740_priv { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; int ident; u16 model; @@ -394,27 +396,6 @@ static enum v4l2_mbus_pixelcode ov9740_codes[] = { V4L2_MBUS_FMT_YUYV8_2X8, }; -static const struct v4l2_queryctrl ov9740_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, -}; - /* read a register */ static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) { @@ -771,36 +752,18 @@ static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) return 0; } -/* Get status of additional camera capabilities */ -static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct ov9740_priv *priv = to_ov9740(sd); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ctrl->value = priv->flag_vflip; - break; - case V4L2_CID_HFLIP: - ctrl->value = priv->flag_hflip; - break; - default: - return -EINVAL; - } - - return 0; -} - /* Set status of additional camera capabilities */ -static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl) { - struct ov9740_priv *priv = to_ov9740(sd); + struct ov9740_priv *priv = + container_of(ctrl->handler, struct ov9740_priv, hdl); switch (ctrl->id) { case V4L2_CID_VFLIP: - priv->flag_vflip = ctrl->value; + priv->flag_vflip = ctrl->val; break; case V4L2_CID_HFLIP: - priv->flag_hflip = ctrl->value; + priv->flag_hflip = ctrl->val; break; default: return -EINVAL; @@ -925,11 +888,6 @@ static int ov9740_video_probe(struct soc_camera_device *icd, return ret; } -static struct soc_camera_ops ov9740_ops = { - .controls = ov9740_controls, - .num_controls = ARRAY_SIZE(ov9740_controls), -}; - /* Request bus settings on camera side */ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) @@ -958,8 +916,6 @@ static struct v4l2_subdev_video_ops ov9740_video_ops = { }; static struct v4l2_subdev_core_ops ov9740_core_ops = { - .g_ctrl = ov9740_g_ctrl, - .s_ctrl = ov9740_s_ctrl, .g_chip_ident = ov9740_g_chip_ident, .s_power = ov9740_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -973,6 +929,10 @@ static struct v4l2_subdev_ops ov9740_subdev_ops = { .video = &ov9740_video_ops, }; +static const struct v4l2_ctrl_ops ov9740_ctrl_ops = { + .s_ctrl = ov9740_s_ctrl, +}; + /* * i2c_driver function */ @@ -980,7 +940,7 @@ static int ov9740_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov9740_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_device *icd = client->dev.platform_data; struct soc_camera_link *icl; int ret; @@ -1002,12 +962,24 @@ static int ov9740_probe(struct i2c_client *client, } v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 13); + v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) { + int err = priv->hdl.error; - icd->ops = &ov9740_ops; + kfree(priv); + return err; + } ret = ov9740_video_probe(icd, client); + if (!ret) + ret = v4l2_ctrl_handler_setup(&priv->hdl); if (ret < 0) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); } @@ -1018,8 +990,9 @@ static int ov9740_remove(struct i2c_client *client) { struct ov9740_priv *priv = i2c_get_clientdata(client); + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); - return 0; } From 2dd7d29c783db1efa875e585770feb2cd7aaaf32 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 06:04:30 -0300 Subject: [PATCH 1347/1596] [media] mt9m001: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 218 ++++++++++++---------------------- 1 file changed, 77 insertions(+), 141 deletions(-) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 3555e853e5c9..42bb3c89cfe6 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -17,6 +17,7 @@ #include #include #include +#include /* * mt9m001 i2c address 0x5d @@ -85,15 +86,19 @@ static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { struct mt9m001 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/auto-exposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; struct v4l2_rect rect; /* Sensor window */ const struct mt9m001_datafmt *fmt; const struct mt9m001_datafmt *fmts; int num_fmts; int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ - unsigned int gain; - unsigned int exposure; + unsigned int total_h; unsigned short y_skip_top; /* Lines to skip at the top */ - unsigned char autoexposure; }; static struct mt9m001 *to_mt9m001(const struct i2c_client *client) @@ -171,10 +176,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); struct v4l2_rect rect = a->c; - struct soc_camera_device *icd = client->dev.platform_data; int ret; const u16 hblank = 9, vblank = 25; - unsigned int total_h; if (mt9m001->fmts == mt9m001_colour_fmts) /* @@ -193,7 +196,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) soc_camera_limit_side(&rect.top, &rect.height, MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); - total_h = rect.height + mt9m001->y_skip_top + vblank; + mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank; /* Blanking and start values - default... */ ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); @@ -213,17 +216,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) if (!ret) ret = reg_write(client, MT9M001_WINDOW_HEIGHT, rect.height + mt9m001->y_skip_top - 1); - if (!ret && mt9m001->autoexposure) { - ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); - if (!ret) { - const struct v4l2_queryctrl *qctrl = - soc_camera_find_qctrl(icd->ops, - V4L2_CID_EXPOSURE); - mt9m001->exposure = (524 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - 1048 + qctrl->minimum; - } - } + if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO) + ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h); if (!ret) mt9m001->rect = rect; @@ -383,105 +377,48 @@ static int mt9m001_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl mt9m001_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9m001_ops = { - .controls = mt9m001_controls, - .num_controls = ARRAY_SIZE(mt9m001_controls), -}; - -static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - int data; + struct mt9m001 *mt9m001 = container_of(ctrl->handler, + struct mt9m001, hdl); + s32 min, max; switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9M001_READ_OPTIONS2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x8000); - break; case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9m001->autoexposure; - break; - case V4L2_CID_GAIN: - ctrl->value = mt9m001->gain; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = mt9m001->exposure; + min = mt9m001->exposure->minimum; + max = mt9m001->exposure->maximum; + mt9m001->exposure->val = + (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min; break; } return 0; } -static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) { + struct mt9m001 *mt9m001 = container_of(ctrl->handler, + struct mt9m001, hdl); + struct v4l2_subdev *sd = &mt9m001->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_device *icd = client->dev.platform_data; - const struct v4l2_queryctrl *qctrl; + struct v4l2_ctrl *exp = mt9m001->exposure; int data; - qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id); - - if (!qctrl) - return -EINVAL; - switch (ctrl->id) { case V4L2_CID_VFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); else data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); if (data < 0) return -EIO; - break; + return 0; + case V4L2_CID_GAIN: - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; /* See Datasheet Table 7, Gain settings. */ - if (ctrl->value <= qctrl->default_value) { + if (ctrl->val <= ctrl->default_value) { /* Pack it into 0..1 step 0.125, register values 0..8 */ - unsigned long range = qctrl->default_value - qctrl->minimum; - data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; + unsigned long range = ctrl->default_value - ctrl->minimum; + data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; dev_dbg(&client->dev, "Setting gain %d\n", data); data = reg_write(client, MT9M001_GLOBAL_GAIN, data); @@ -490,8 +427,8 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) } else { /* Pack it into 1.125..15 variable step, register values 9..67 */ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ - unsigned long range = qctrl->maximum - qctrl->default_value - 1; - unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * + unsigned long range = ctrl->maximum - ctrl->default_value - 1; + unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * 111 + range / 2) / range + 9; if (gain <= 32) @@ -507,47 +444,30 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (data < 0) return -EIO; } + return 0; - /* Success */ - mt9m001->gain = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - /* mt9m001 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - unsigned long range = qctrl->maximum - qctrl->minimum; - unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_MANUAL) { + unsigned long range = exp->maximum - exp->minimum; + unsigned long shutter = ((exp->val - exp->minimum) * 1048 + range / 2) / range + 1; dev_dbg(&client->dev, "Setting shutter width from %d to %lu\n", - reg_read(client, MT9M001_SHUTTER_WIDTH), - shutter); + reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) return -EIO; - mt9m001->exposure = ctrl->value; - mt9m001->autoexposure = 0; - } - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) { + } else { const u16 vblank = 25; - unsigned int total_h = mt9m001->rect.height + + + mt9m001->total_h = mt9m001->rect.height + mt9m001->y_skip_top + vblank; - if (reg_write(client, MT9M001_SHUTTER_WIDTH, - total_h) < 0) + if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0) return -EIO; - qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); - mt9m001->exposure = (524 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - 1048 + qctrl->minimum; - mt9m001->autoexposure = 1; - } else - mt9m001->autoexposure = 0; - break; + } + return 0; } - return 0; + return -EINVAL; } /* @@ -621,10 +541,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, dev_err(&client->dev, "Failed to initialise the camera\n"); /* mt9m001_init() has reset the chip, returning registers to defaults */ - mt9m001->gain = 64; - mt9m001->exposure = 255; - - return ret; + return v4l2_ctrl_handler_setup(&mt9m001->hdl); } static void mt9m001_video_remove(struct soc_camera_device *icd) @@ -647,9 +564,12 @@ static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) return 0; } +static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = { + .g_volatile_ctrl = mt9m001_g_volatile_ctrl, + .s_ctrl = mt9m001_s_ctrl, +}; + static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { - .g_ctrl = mt9m001_g_ctrl, - .s_ctrl = mt9m001_s_ctrl, .g_chip_ident = mt9m001_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9m001_g_register, @@ -765,25 +685,40 @@ static int mt9m001_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); + v4l2_ctrl_handler_init(&mt9m001->hdl, 4); + v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 64); + mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 255, 1, 255); + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl, + &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9m001->subdev.ctrl_handler = &mt9m001->hdl; + if (mt9m001->hdl.error) { + int err = mt9m001->hdl.error; - /* Second stage probe - when a capture adapter is there */ - icd->ops = &mt9m001_ops; + kfree(mt9m001); + return err; + } + v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure, + V4L2_EXPOSURE_MANUAL, true); + /* Second stage probe - when a capture adapter is there */ mt9m001->y_skip_top = 0; mt9m001->rect.left = MT9M001_COLUMN_SKIP; mt9m001->rect.top = MT9M001_ROW_SKIP; mt9m001->rect.width = MT9M001_MAX_WIDTH; mt9m001->rect.height = MT9M001_MAX_HEIGHT; - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9m001->autoexposure = 1; - ret = mt9m001_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&mt9m001->hdl); kfree(mt9m001); } @@ -795,7 +730,8 @@ static int mt9m001_remove(struct i2c_client *client) struct mt9m001 *mt9m001 = to_mt9m001(client); struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&mt9m001->subdev); + v4l2_ctrl_handler_free(&mt9m001->hdl); mt9m001_video_remove(icd); kfree(mt9m001); From af8425c54beb3c32cbb503a379132b3975535289 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 06:56:57 -0300 Subject: [PATCH 1348/1596] [media] mt9m111: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m111.c | 203 ++++++++-------------------------- 1 file changed, 48 insertions(+), 155 deletions(-) diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 28d447c6d40e..8cacbf016848 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* @@ -178,6 +179,8 @@ enum mt9m111_context { struct mt9m111 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *gain; int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code * from v4l2-chip-ident.h */ enum mt9m111_context context; @@ -186,13 +189,8 @@ struct mt9m111 { int power_count; const struct mt9m111_datafmt *fmt; int lastpage; /* PageMap cache value */ - unsigned int gain; - unsigned char autoexposure; unsigned char datawidth; unsigned int powered:1; - unsigned int hflip:1; - unsigned int vflip:1; - unsigned int autowhitebalance:1; }; static struct mt9m111 *to_mt9m111(const struct i2c_client *client) @@ -646,48 +644,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl mt9m111_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Verticaly", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontaly", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { /* gain = 1/32*val (=>gain=1 if val==32) */ - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 63 * 2 * 2, - .step = 1, - .default_value = 32, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9m111_ops = { - .controls = mt9m111_controls, - .num_controls = ARRAY_SIZE(mt9m111_controls), -}; - static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); @@ -728,7 +684,6 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) if (gain > 63 * 2 * 2) return -EINVAL; - mt9m111->gain = gain; if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) val = (1 << 10) | (1 << 9) | (gain / 4); else if ((gain >= 64) && (gain < 64 * 2)) @@ -742,118 +697,47 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int ret; if (on) - ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); - else - ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); - - if (!ret) - mt9m111->autoexposure = on; - - return ret; + return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); + return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); } static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int ret; if (on) - ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); - else - ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); - - if (!ret) - mt9m111->autowhitebalance = on; - - return ret; + return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); + return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); } -static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - int data; + struct mt9m111 *mt9m111 = container_of(ctrl->handler, + struct mt9m111, hdl); switch (ctrl->id) { case V4L2_CID_VFLIP: - if (mt9m111->context == HIGHPOWER) - data = reg_read(READ_MODE_B); - else - data = reg_read(READ_MODE_A); - - if (data < 0) - return -EIO; - ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); - break; - case V4L2_CID_HFLIP: - if (mt9m111->context == HIGHPOWER) - data = reg_read(READ_MODE_B); - else - data = reg_read(READ_MODE_A); - - if (data < 0) - return -EIO; - ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); - break; - case V4L2_CID_GAIN: - data = mt9m111_get_global_gain(mt9m111); - if (data < 0) - return data; - ctrl->value = data; - break; - case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9m111->autoexposure; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - ctrl->value = mt9m111->autowhitebalance; - break; - } - return 0; -} - -static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - const struct v4l2_queryctrl *qctrl; - int ret; - - qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); - if (!qctrl) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - mt9m111->vflip = ctrl->value; - ret = mt9m111_set_flip(mt9m111, ctrl->value, + return mt9m111_set_flip(mt9m111, ctrl->val, MT9M111_RMB_MIRROR_ROWS); - break; case V4L2_CID_HFLIP: - mt9m111->hflip = ctrl->value; - ret = mt9m111_set_flip(mt9m111, ctrl->value, + return mt9m111_set_flip(mt9m111, ctrl->val, MT9M111_RMB_MIRROR_COLS); - break; case V4L2_CID_GAIN: - ret = mt9m111_set_global_gain(mt9m111, ctrl->value); - break; + return mt9m111_set_global_gain(mt9m111, ctrl->val); case V4L2_CID_EXPOSURE_AUTO: - ret = mt9m111_set_autoexposure(mt9m111, ctrl->value); - break; + return mt9m111_set_autoexposure(mt9m111, ctrl->val); case V4L2_CID_AUTO_WHITE_BALANCE: - ret = mt9m111_set_autowhitebalance(mt9m111, ctrl->value); - break; - default: - ret = -EINVAL; + return mt9m111_set_autowhitebalance(mt9m111, ctrl->val); } - return ret; + return -EINVAL; } static int mt9m111_suspend(struct mt9m111 *mt9m111) { - mt9m111->gain = mt9m111_get_global_gain(mt9m111); + v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111)); return 0; } @@ -863,11 +747,7 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111) mt9m111_set_context(mt9m111, mt9m111->context); mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); mt9m111_setup_rect(mt9m111, &mt9m111->rect); - mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); - mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); - mt9m111_set_global_gain(mt9m111, mt9m111->gain); - mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); - mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance); + v4l2_ctrl_handler_setup(&mt9m111->hdl); } static int mt9m111_resume(struct mt9m111 *mt9m111) @@ -895,8 +775,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111) ret = mt9m111_reset(mt9m111); if (!ret) ret = mt9m111_set_context(mt9m111, mt9m111->context); - if (!ret) - ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); if (ret) dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); return ret; @@ -919,9 +797,6 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, mt9m111->lastpage = -1; - mt9m111->autoexposure = 1; - mt9m111->autowhitebalance = 1; - data = reg_read(CHIP_VERSION); switch (data) { @@ -935,17 +810,16 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); break; default: - ret = -ENODEV; dev_err(&client->dev, "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", data); - goto ei2c; + return -ENODEV; } ret = mt9m111_init(mt9m111); - -ei2c: - return ret; + if (ret) + return ret; + return v4l2_ctrl_handler_setup(&mt9m111->hdl); } static int mt9m111_s_power(struct v4l2_subdev *sd, int on) @@ -982,9 +856,11 @@ static int mt9m111_s_power(struct v4l2_subdev *sd, int on) return ret; } +static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = { + .s_ctrl = mt9m111_s_ctrl, +}; + static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { - .g_ctrl = mt9m111_g_ctrl, - .s_ctrl = mt9m111_s_ctrl, .g_chip_ident = mt9m111_g_chip_ident, .s_power = mt9m111_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -1066,10 +942,27 @@ static int mt9m111_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); + v4l2_ctrl_handler_init(&mt9m111->hdl, 5); + v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, + V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32); + v4l2_ctrl_new_std_menu(&mt9m111->hdl, + &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9m111->subdev.ctrl_handler = &mt9m111->hdl; + if (mt9m111->hdl.error) { + int err = mt9m111->hdl.error; - /* Second stage probe - when a capture adapter is there */ - icd->ops = &mt9m111_ops; + kfree(mt9m111); + return err; + } + /* Second stage probe - when a capture adapter is there */ mt9m111->rect.left = MT9M111_MIN_DARK_COLS; mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; mt9m111->rect.width = MT9M111_MAX_WIDTH; @@ -1078,7 +971,7 @@ static int mt9m111_probe(struct i2c_client *client, ret = mt9m111_video_probe(icd, client); if (ret) { - icd->ops = NULL; + v4l2_ctrl_handler_free(&mt9m111->hdl); kfree(mt9m111); } @@ -1088,9 +981,9 @@ static int mt9m111_probe(struct i2c_client *client, static int mt9m111_remove(struct i2c_client *client) { struct mt9m111 *mt9m111 = to_mt9m111(client); - struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + v4l2_device_unregister_subdev(&mt9m111->subdev); + v4l2_ctrl_handler_free(&mt9m111->hdl); kfree(mt9m111); return 0; From 41efcd7a6862951fd13c0e950ef05b865d7488a8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Sep 2011 06:08:51 -0300 Subject: [PATCH 1349/1596] [media] mt9t031: convert to the control framework Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t031.c | 252 ++++++++++++---------------------- 1 file changed, 86 insertions(+), 166 deletions(-) diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 25fb833f6f2c..7ce37990a446 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -19,6 +19,7 @@ #include #include #include +#include /* * mt9t031 i2c address 0x5d @@ -60,14 +61,18 @@ struct mt9t031 { struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + struct { + /* exposure/auto-exposure cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; struct v4l2_rect rect; /* Sensor window */ int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ u16 xskip; u16 yskip; - unsigned int gain; + unsigned int total_h; unsigned short y_skip_top; /* Lines to skip at the top */ - unsigned int exposure; - unsigned char autoexposure; }; static struct mt9t031 *to_mt9t031(const struct i2c_client *client) @@ -175,69 +180,6 @@ static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -enum { - MT9T031_CTRL_VFLIP, - MT9T031_CTRL_HFLIP, - MT9T031_CTRL_GAIN, - MT9T031_CTRL_EXPOSURE, - MT9T031_CTRL_EXPOSURE_AUTO, -}; - -static const struct v4l2_queryctrl mt9t031_controls[] = { - [MT9T031_CTRL_VFLIP] = { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - [MT9T031_CTRL_HFLIP] = { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - [MT9T031_CTRL_GAIN] = { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, - [MT9T031_CTRL_EXPOSURE] = { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, - [MT9T031_CTRL_EXPOSURE_AUTO] = { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9t031_ops = { - .controls = mt9t031_controls, - .num_controls = ARRAY_SIZE(mt9t031_controls), -}; - /* target must be _even_ */ static u16 mt9t031_skip(s32 *source, s32 target, s32 max) { @@ -334,17 +276,10 @@ static int mt9t031_set_params(struct i2c_client *client, if (ret >= 0) ret = reg_write(client, MT9T031_WINDOW_HEIGHT, rect->height + mt9t031->y_skip_top - 1); - if (ret >= 0 && mt9t031->autoexposure) { - unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; - ret = set_shutter(client, total_h); - if (ret >= 0) { - const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - const struct v4l2_queryctrl *qctrl = - &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - shutter_max + qctrl->minimum; - } + if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) { + mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank; + + ret = set_shutter(client, mt9t031->total_h); } /* Re-enable register update, commit all changes */ @@ -513,71 +448,57 @@ static int mt9t031_s_register(struct v4l2_subdev *sd, } #endif -static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - int data; + struct mt9t031 *mt9t031 = container_of(ctrl->handler, + struct mt9t031, hdl); + const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK; + s32 min, max; switch (ctrl->id) { - case V4L2_CID_VFLIP: - data = reg_read(client, MT9T031_READ_MODE_2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x8000); - break; - case V4L2_CID_HFLIP: - data = reg_read(client, MT9T031_READ_MODE_2); - if (data < 0) - return -EIO; - ctrl->value = !!(data & 0x4000); - break; case V4L2_CID_EXPOSURE_AUTO: - ctrl->value = mt9t031->autoexposure; - break; - case V4L2_CID_GAIN: - ctrl->value = mt9t031->gain; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = mt9t031->exposure; + min = mt9t031->exposure->minimum; + max = mt9t031->exposure->maximum; + mt9t031->exposure->val = + (shutter_max / 2 + (mt9t031->total_h - 1) * (max - min)) + / shutter_max + min; break; } return 0; } -static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl) { + struct mt9t031 *mt9t031 = container_of(ctrl->handler, + struct mt9t031, hdl); + struct v4l2_subdev *sd = &mt9t031->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t031 *mt9t031 = to_mt9t031(client); - const struct v4l2_queryctrl *qctrl; + struct v4l2_ctrl *exp = mt9t031->exposure; int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); else data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_HFLIP: - if (ctrl->value) + if (ctrl->val) data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); else data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); if (data < 0) return -EIO; - break; + return 0; case V4L2_CID_GAIN: - qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; /* See Datasheet Table 7, Gain settings. */ - if (ctrl->value <= qctrl->default_value) { + if (ctrl->val <= ctrl->default_value) { /* Pack it into 0..1 step 0.125, register values 0..8 */ - unsigned long range = qctrl->default_value - qctrl->minimum; - data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; + unsigned long range = ctrl->default_value - ctrl->minimum; + data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; dev_dbg(&client->dev, "Setting gain %d\n", data); data = reg_write(client, MT9T031_GLOBAL_GAIN, data); @@ -586,9 +507,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) } else { /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ - unsigned long range = qctrl->maximum - qctrl->default_value - 1; + unsigned long range = ctrl->maximum - ctrl->default_value - 1; /* calculated gain: map 65..127 to 9..1024 step 0.125 */ - unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * + unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * 1015 + range / 2) / range + 9; if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ @@ -605,19 +526,13 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (data < 0) return -EIO; } + return 0; - /* Success */ - mt9t031->gain = ctrl->value; - break; - case V4L2_CID_EXPOSURE: - qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - /* mt9t031 has maximum == default */ - if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) - return -EINVAL; - else { - const unsigned long range = qctrl->maximum - qctrl->minimum; - const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 + - range / 2) / range + 1; + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_MANUAL) { + unsigned int range = exp->maximum - exp->minimum; + unsigned int shutter = ((exp->val - exp->minimum) * 1048 + + range / 2) / range + 1; u32 old; get_shutter(client, &old); @@ -625,27 +540,15 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) old, shutter); if (set_shutter(client, shutter) < 0) return -EIO; - mt9t031->exposure = ctrl->value; - mt9t031->autoexposure = 0; - } - break; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->value) { + } else { const u16 vblank = MT9T031_VERTICAL_BLANK; - const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - unsigned int total_h = mt9t031->rect.height + + mt9t031->total_h = mt9t031->rect.height + mt9t031->y_skip_top + vblank; - if (set_shutter(client, total_h) < 0) + if (set_shutter(client, mt9t031->total_h) < 0) return -EIO; - qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; - mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * - (qctrl->maximum - qctrl->minimum)) / - shutter_max + qctrl->minimum; - mt9t031->autoexposure = 1; - } else - mt9t031->autoexposure = 0; - break; + } + return 0; default: return -EINVAL; } @@ -735,15 +638,12 @@ static int mt9t031_video_probe(struct i2c_client *client) dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); ret = mt9t031_idle(client); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "Failed to initialise the camera\n"); - else + } else { vdev->dev.type = &mt9t031_dev_type; - - /* mt9t031_idle() has reset the chip to default. */ - mt9t031->exposure = 255; - mt9t031->gain = 64; - + v4l2_ctrl_handler_setup(&mt9t031->hdl); + } return ret; } @@ -757,9 +657,12 @@ static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) return 0; } +static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { + .g_volatile_ctrl = mt9t031_g_volatile_ctrl, + .s_ctrl = mt9t031_s_ctrl, +}; + static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { - .g_ctrl = mt9t031_g_ctrl, - .s_ctrl = mt9t031_s_ctrl, .g_chip_ident = mt9t031_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9t031_g_register, @@ -844,8 +747,6 @@ static int mt9t031_probe(struct i2c_client *client, dev_err(&client->dev, "MT9T031 driver needs platform data\n"); return -EINVAL; } - - icd->ops = &mt9t031_ops; } if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { @@ -859,6 +760,33 @@ static int mt9t031_probe(struct i2c_client *client, return -ENOMEM; v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); + v4l2_ctrl_handler_init(&mt9t031->hdl, 5); + v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 64); + + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ + mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl, + &mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, + V4L2_EXPOSURE_AUTO); + mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 255, 1, 255); + + mt9t031->subdev.ctrl_handler = &mt9t031->hdl; + if (mt9t031->hdl.error) { + int err = mt9t031->hdl.error; + + kfree(mt9t031); + return err; + } + v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure, + V4L2_EXPOSURE_MANUAL, true); mt9t031->y_skip_top = 0; mt9t031->rect.left = MT9T031_COLUMN_SKIP; @@ -866,12 +794,6 @@ static int mt9t031_probe(struct i2c_client *client, mt9t031->rect.width = MT9T031_MAX_WIDTH; mt9t031->rect.height = MT9T031_MAX_HEIGHT; - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9t031->autoexposure = 1; - mt9t031->xskip = 1; mt9t031->yskip = 1; @@ -882,8 +804,7 @@ static int mt9t031_probe(struct i2c_client *client, mt9t031_disable(client); if (ret) { - if (icd) - icd->ops = NULL; + v4l2_ctrl_handler_free(&mt9t031->hdl); kfree(mt9t031); } @@ -893,10 +814,9 @@ static int mt9t031_probe(struct i2c_client *client, static int mt9t031_remove(struct i2c_client *client) { struct mt9t031 *mt9t031 = to_mt9t031(client); - struct soc_camera_device *icd = client->dev.platform_data; - if (icd) - icd->ops = NULL; + v4l2_device_unregister_subdev(&mt9t031->subdev); + v4l2_ctrl_handler_free(&mt9t031->hdl); kfree(mt9t031); return 0; From 0934d94a52423fac35922c2e29d72a43db7ddd48 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 8 Sep 2011 13:16:56 -0300 Subject: [PATCH 1350/1596] [media] soc_camera: remove the now obsolete struct soc_camera_ops Signed-off-by: Hans Verkuil [g.liakhovetski@gmx.de: mt9m001 hunk moved to an earlier patch] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 1 - drivers/media/video/mt9t112.c | 2 -- drivers/media/video/ov5642.c | 1 - drivers/media/video/soc_camera_platform.c | 2 -- drivers/media/video/tw9910.c | 1 - include/media/soc_camera.h | 18 ------------------ 6 files changed, 25 deletions(-) diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 20756e03dbb1..3f5d4de8b91b 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -437,7 +437,6 @@ static int imx074_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); - icd->ops = NULL; priv->fmt = &imx074_colour_fmts[0]; ret = imx074_video_probe(icd, client); diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 25cdcb90768a..b8da7fe9a6bd 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -1095,8 +1095,6 @@ static int mt9t112_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - icd->ops = NULL; - ret = mt9t112_camera_probe(icd, client); if (ret) kfree(priv); diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index b36d42bfeab2..163a6f7ff8ef 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -942,7 +942,6 @@ static int ov5642_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); - icd->ops = NULL; priv->fmt = &ov5642_colour_fmts[0]; ret = ov5642_video_probe(icd, client); diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index c8f6b188496d..4402a8a74f7a 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -150,8 +150,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev) /* Set the control device reference */ icd->control = &pdev->dev; - icd->ops = NULL; - ici = to_soc_camera_host(icd->parent); v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 40cc1494b377..2fddd1fbe529 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -921,7 +921,6 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - icd->ops = NULL; icd->iface = icl->bus_id; ret = tw9910_video_probe(icd, client); diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index d41b8bd74445..6398ff0f08ab 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -39,7 +39,6 @@ struct soc_camera_device { unsigned char iface; /* Host number */ unsigned char devnum; /* Device number per host */ struct soc_camera_sense *sense; /* See comment in struct definition */ - struct soc_camera_ops *ops; struct video_device *vdev; struct v4l2_ctrl_handler ctrl_handler; const struct soc_camera_format_xlate *current_fmt; @@ -192,11 +191,6 @@ struct soc_camera_format_xlate { const struct soc_mbus_pixelfmt *host_fmt; }; -struct soc_camera_ops { - const struct v4l2_queryctrl *controls; - int num_controls; -}; - #define SOCAM_SENSE_PCLK_CHANGED (1 << 0) /** @@ -223,18 +217,6 @@ struct soc_camera_sense { unsigned long pixel_clock; }; -static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( - struct soc_camera_ops *ops, int id) -{ - int i; - - for (i = 0; i < ops->num_controls; i++) - if (ops->controls[i].id == id) - return &ops->controls[i]; - - return NULL; -} - #define SOCAM_DATAWIDTH(x) BIT((x) - 1) #define SOCAM_DATAWIDTH_4 SOCAM_DATAWIDTH(4) #define SOCAM_DATAWIDTH_8 SOCAM_DATAWIDTH(8) From 09362ec25c3f42d00a4008d0622bfbca68e540f5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 7 Sep 2011 18:07:23 -0300 Subject: [PATCH 1351/1596] [media] V4L: docbook documentation for struct v4l2_create_buffers Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-compat-ioctl32.c | 13 +++++++++++-- include/linux/videodev2.h | 14 +++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index e77e0cfc9312..c68531b88279 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -159,11 +159,20 @@ struct v4l2_format32 { } fmt; }; +/** + * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument + * @index: on return, index of the first created buffer + * @count: entry: number of requested buffers, + * return: number of created buffers + * @memory: buffer memory type + * @format: frame format, for which buffers are requested + * @reserved: future extensions + */ struct v4l2_create_buffers32 { - __u32 index; /* output: buffers index...index + count - 1 have been created */ + __u32 index; __u32 count; enum v4l2_memory memory; - struct v4l2_format32 format; /* filled in by the user, plane sizes calculated by the driver */ + struct v4l2_format32 format; __u32 reserved[8]; }; diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index cd512f07beed..66945a6f628d 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -2142,12 +2142,20 @@ struct v4l2_dbg_chip_ident { __u32 revision; /* chip revision, chip specific */ } __attribute__ ((packed)); -/* VIDIOC_CREATE_BUFS */ +/** + * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument + * @index: on return, index of the first created buffer + * @count: entry: number of requested buffers, + * return: number of created buffers + * @memory: buffer memory type + * @format: frame format, for which buffers are requested + * @reserved: future extensions + */ struct v4l2_create_buffers { - __u32 index; /* output: buffers index...index + count - 1 have been created */ + __u32 index; __u32 count; enum v4l2_memory memory; - struct v4l2_format format; /* "type" is used always, the rest if sizeimage == 0 */ + struct v4l2_format format; __u32 reserved[8]; }; From 14178aa57ce6ac4f05b4df8ea9e010486ce83a76 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 21 Sep 2011 15:16:30 -0300 Subject: [PATCH 1352/1596] [media] V4L: soc-camera: start removing struct soc_camera_device from client drivers Remove most trivial uses of struct soc_camera_device from most client drivers, abstracting some of them inside inline functions. Next steps will eliminate remaining uses and modify inline functions to not use struct soc_camera_device. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 17 +++--------- drivers/media/video/mt9m001.c | 39 ++++++++------------------- drivers/media/video/mt9m111.c | 24 ++++------------- drivers/media/video/mt9t031.c | 22 ++++++---------- drivers/media/video/mt9t112.c | 45 ++++++++++++-------------------- drivers/media/video/mt9v022.c | 44 ++++++++----------------------- drivers/media/video/ov2640.c | 27 +++++-------------- drivers/media/video/ov5642.c | 17 +++--------- drivers/media/video/ov6650.c | 20 ++++---------- drivers/media/video/ov772x.c | 31 +++++++--------------- drivers/media/video/ov9640.c | 21 +++------------ drivers/media/video/ov9740.c | 21 +++------------ drivers/media/video/rj54n1cb0c.c | 27 +++++-------------- drivers/media/video/tw9910.c | 32 +++++++---------------- include/media/soc_camera.h | 25 +++++++++++++++--- 15 files changed, 126 insertions(+), 286 deletions(-) diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 3f5d4de8b91b..4f3ce7fa87df 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -298,8 +298,7 @@ static struct v4l2_subdev_ops imx074_subdev_ops = { .video = &imx074_subdev_video_ops, }; -static int imx074_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int imx074_video_probe(struct i2c_client *client) { int ret; u16 id; @@ -409,17 +408,10 @@ static int imx074_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct imx074 *priv; - struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "IMX074: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "IMX074: missing platform data!\n"); return -EINVAL; @@ -439,7 +431,7 @@ static int imx074_probe(struct i2c_client *client, priv->fmt = &imx074_colour_fmts[0]; - ret = imx074_video_probe(icd, client); + ret = imx074_video_probe(client); if (ret < 0) { kfree(priv); return ret; @@ -451,8 +443,7 @@ static int imx074_probe(struct i2c_client *client, static int imx074_remove(struct i2c_client *client) { struct imx074 *priv = to_imx074(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); if (icl->free_bus) icl->free_bus(icl); diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 42bb3c89cfe6..58cdcedf53de 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -205,7 +205,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) /* * The caller provides a supported format, as verified per - * call to icd->try_fmt() + * call to .try_mbus_fmt() */ if (!ret) ret = reg_write(client, MT9M001_COLUMN_START, rect.left); @@ -474,19 +474,14 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int mt9m001_video_probe(struct soc_camera_device *icd, +static int mt9m001_video_probe(struct soc_camera_link *icl, struct i2c_client *client) { struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); s32 data; unsigned long flags; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* Enable the chip */ data = reg_write(client, MT9M001_CHIP_ENABLE, 1); dev_dbg(&client->dev, "write: %d\n", data); @@ -544,12 +539,8 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, return v4l2_ctrl_handler_setup(&mt9m001->hdl); } -static void mt9m001_video_remove(struct soc_camera_device *icd) +static void mt9m001_video_remove(struct soc_camera_link *icl) { - struct soc_camera_link *icl = to_soc_camera_link(icd); - - dev_dbg(icd->pdev, "Video removed: %p, %p\n", - icd->parent, icd->vdev); if (icl->free_bus) icl->free_bus(icl); } @@ -594,8 +585,7 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); /* MT9M001 has all capture_format parameters fixed */ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -610,9 +600,9 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + const struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_device *icd = soc_camera_from_i2c(client); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); /* * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that * is the number of bits, that the host has to sample, not the number of @@ -658,17 +648,10 @@ static int mt9m001_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m001 *mt9m001; - struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "MT9M001 driver needs platform data\n"); return -EINVAL; @@ -716,7 +699,7 @@ static int mt9m001_probe(struct i2c_client *client, mt9m001->rect.width = MT9M001_MAX_WIDTH; mt9m001->rect.height = MT9M001_MAX_HEIGHT; - ret = mt9m001_video_probe(icd, client); + ret = mt9m001_video_probe(icl, client); if (ret) { v4l2_ctrl_handler_free(&mt9m001->hdl); kfree(mt9m001); @@ -728,11 +711,11 @@ static int mt9m001_probe(struct i2c_client *client, static int mt9m001_remove(struct i2c_client *client) { struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); v4l2_device_unregister_subdev(&mt9m001->subdev); v4l2_ctrl_handler_free(&mt9m001->hdl); - mt9m001_video_remove(icd); + mt9m001_video_remove(icl); kfree(mt9m001); return 0; diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 8cacbf016848..9feeb0cb6722 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -784,19 +784,12 @@ static int mt9m111_init(struct mt9m111 *mt9m111) * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int mt9m111_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int mt9m111_video_probe(struct i2c_client *client) { struct mt9m111 *mt9m111 = to_mt9m111(client); s32 data; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - - mt9m111->lastpage = -1; - data = reg_read(CHIP_VERSION); switch (data) { @@ -883,8 +876,7 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | @@ -915,17 +907,10 @@ static int mt9m111_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m111 *mt9m111; - struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "mt9m111: soc-camera data missing!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "mt9m111: driver needs platform data\n"); return -EINVAL; @@ -968,8 +953,9 @@ static int mt9m111_probe(struct i2c_client *client, mt9m111->rect.width = MT9M111_MAX_WIDTH; mt9m111->rect.height = MT9M111_MAX_HEIGHT; mt9m111->fmt = &mt9m111_colour_fmts[0]; + mt9m111->lastpage = -1; - ret = mt9m111_video_probe(icd, client); + ret = mt9m111_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&mt9m111->hdl); kfree(mt9m111); diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 7ce37990a446..95cd602ae4ec 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -265,7 +265,7 @@ static int mt9t031_set_params(struct i2c_client *client, /* * The caller provides a supported format, as guaranteed by - * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() + * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap() */ if (ret >= 0) ret = reg_write(client, MT9T031_COLUMN_START, rect->left); @@ -573,8 +573,7 @@ static int mt9t031_runtime_suspend(struct device *dev) static int mt9t031_runtime_resume(struct device *dev) { struct video_device *vdev = to_video_device(dev); - struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev); struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t031 *mt9t031 = to_mt9t031(client); @@ -684,8 +683,7 @@ static int mt9t031_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -700,8 +698,7 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_FALLING) @@ -737,16 +734,13 @@ static int mt9t031_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9t031 *mt9t031; - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int ret; - if (icd) { - struct soc_camera_link *icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "MT9T031 driver needs platform data\n"); - return -EINVAL; - } + if (!icl) { + dev_err(&client->dev, "MT9T031 driver needs platform data\n"); + return -EINVAL; } if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index b8da7fe9a6bd..5b045a1097c6 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -89,7 +89,6 @@ struct mt9t112_priv { struct v4l2_subdev subdev; struct mt9t112_camera_info *info; struct i2c_client *client; - struct soc_camera_device icd; struct v4l2_rect frame; const struct mt9t112_format *format; int model; @@ -306,38 +305,38 @@ static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) n = (n >> 8) & 0x003f; enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; - dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); + dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); vco = 2 * m * ext / (n+1); enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; - dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable); + dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); clk = vco / (p1+1) / (p2+1); enable = (96000 < clk) ? "X" : ""; - dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); clk = vco / (p3+1); enable = (768000 < clk) ? "X" : ""; - dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); clk = vco / (p6+1); enable = (96000 < clk) ? "X" : ""; - dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); clk = vco / (p5+1); enable = (54000 < clk) ? "X" : ""; - dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); clk = vco / (p4+1); enable = (70000 < clk) ? "X" : ""; - dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); clk = vco / (p7+1); - dev_info(&client->dev, "External sensor : %10u K\n", clk); + dev_dbg(&client->dev, "External sensor : %10u K\n", clk); clk = ext / (n+1); enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; - dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable); + dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); return 0; } @@ -982,8 +981,7 @@ static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | @@ -998,8 +996,7 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct mt9t112_priv *priv = to_mt9t112(client); if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) @@ -1029,17 +1026,12 @@ static struct v4l2_subdev_ops mt9t112_subdev_ops = { .video = &mt9t112_subdev_video_ops, }; -static int mt9t112_camera_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int mt9t112_camera_probe(struct i2c_client *client) { struct mt9t112_priv *priv = to_mt9t112(client); const char *devname; int chipid; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show chip ID */ @@ -1068,8 +1060,7 @@ static int mt9t112_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9t112_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct v4l2_rect rect = { .width = VGA_WIDTH, .height = VGA_HEIGHT, @@ -1078,15 +1069,11 @@ static int mt9t112_probe(struct i2c_client *client, }; int ret; - if (!icd) { - dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); + if (!icl || !icl->priv) { + dev_err(&client->dev, "mt9t112: missing platform data!\n"); return -EINVAL; } - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) - return -EINVAL; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -1095,7 +1082,7 @@ static int mt9t112_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - ret = mt9t112_camera_probe(icd, client); + ret = mt9t112_camera_probe(client); if (ret) kfree(priv); diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 7e2aeda21752..72b179b2ad6c 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -332,7 +332,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, /* * The caller provides a supported format, as verified per call to - * icd->try_fmt(), datawidth is from our supported format list + * .try_mbus_fmt(), datawidth is from our supported format list */ switch (mf->code) { case V4L2_MBUS_FMT_Y8_1X8: @@ -562,19 +562,14 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int mt9v022_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int mt9v022_video_probe(struct i2c_client *client) { struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); s32 data; int ret; unsigned long flags; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* Read out the chip version register */ data = reg_read(client, MT9V022_CHIP_VERSION); @@ -648,16 +643,6 @@ static int mt9v022_video_probe(struct soc_camera_device *icd, return ret; } -static void mt9v022_video_remove(struct soc_camera_device *icd) -{ - struct soc_camera_link *icl = to_soc_camera_link(icd); - - dev_dbg(icd->pdev, "Video removed: %p, %p\n", - icd->parent, icd->vdev); - if (icl->free_bus) - icl->free_bus(icl); -} - static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -698,8 +683,7 @@ static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -730,8 +714,8 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, int ret; u16 pixclk = 0; - dev_info(icd->pdev, "set %d: %s, %dbps\n", icd->current_fmt->code, - icd->current_fmt->host_fmt->name, bps); + dev_dbg(icd->pdev, "set %d: %s, %dbps\n", icd->current_fmt->code, + icd->current_fmt->host_fmt->name, bps); if (icl->set_bus_param) { ret = icl->set_bus_param(icl, 1 << (bps - 1)); @@ -798,17 +782,10 @@ static int mt9v022_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9v022 *mt9v022; - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; int ret; - if (!icd) { - dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "MT9V022 driver needs platform data\n"); return -EINVAL; @@ -868,7 +845,7 @@ static int mt9v022_probe(struct i2c_client *client, mt9v022->rect.width = MT9V022_MAX_WIDTH; mt9v022->rect.height = MT9V022_MAX_HEIGHT; - ret = mt9v022_video_probe(icd, client); + ret = mt9v022_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&mt9v022->hdl); kfree(mt9v022); @@ -880,10 +857,11 @@ static int mt9v022_probe(struct i2c_client *client, static int mt9v022_remove(struct i2c_client *client) { struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); v4l2_device_unregister_subdev(&mt9v022->subdev); - mt9v022_video_remove(icd); + if (icl->free_bus) + icl->free_bus(icl); v4l2_ctrl_handler_free(&mt9v022->hdl); kfree(mt9v022); diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 981767f2d8ea..d37a5cceebb6 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -942,18 +942,13 @@ static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov2640_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov2640_video_probe(struct i2c_client *client) { struct ov2640_priv *priv = to_ov2640(client); u8 pid, ver, midh, midl; const char *devname; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show product ID and manufacturer ID */ @@ -1001,8 +996,7 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -1035,18 +1029,11 @@ static struct v4l2_subdev_ops ov2640_subdev_ops = { static int ov2640_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct ov2640_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&adapter->dev, "OV2640: missing soc-camera data!\n"); - return -EINVAL; - } + struct ov2640_priv *priv; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&adapter->dev, "OV2640: Missing platform_data for driver\n"); @@ -1080,7 +1067,7 @@ static int ov2640_probe(struct i2c_client *client, return err; } - ret = ov2640_video_probe(icd, client); + ret = ov2640_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 163a6f7ff8ef..2a26602fc86d 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -889,8 +889,7 @@ static struct v4l2_subdev_ops ov5642_subdev_ops = { .video = &ov5642_subdev_video_ops, }; -static int ov5642_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov5642_video_probe(struct i2c_client *client) { int ret; u8 id_high, id_low; @@ -921,16 +920,9 @@ static int ov5642_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov5642 *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "OV5642: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "OV5642: missing platform data!\n"); return -EINVAL; @@ -944,7 +936,7 @@ static int ov5642_probe(struct i2c_client *client, priv->fmt = &ov5642_colour_fmts[0]; - ret = ov5642_video_probe(icd, client); + ret = ov5642_video_probe(client); if (ret < 0) goto error; @@ -958,8 +950,7 @@ static int ov5642_probe(struct i2c_client *client, static int ov5642_remove(struct i2c_client *client) { struct ov5642 *priv = to_ov5642(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); if (icl->free_bus) icl->free_bus(icl); diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index efa45132c992..f060eaaf916f 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -820,8 +820,7 @@ static int ov6650_prog_dflt(struct i2c_client *client) return ret; } -static int ov6650_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov6650_video_probe(struct i2c_client *client) { u8 pidh, pidl, midh, midl; int ret = 0; @@ -875,8 +874,7 @@ static int ov6650_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -894,8 +892,7 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); unsigned long flags = soc_camera_apply_board_flags(icl, cfg); int ret; @@ -948,16 +945,9 @@ static int ov6650_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov6650 *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "Missing platform_data for driver\n"); return -EINVAL; @@ -1020,7 +1010,7 @@ static int ov6650_probe(struct i2c_client *client, priv->code = V4L2_MBUS_FMT_YUYV8_2X8; priv->colorspace = V4L2_COLORSPACE_JPEG; - ret = ov6650_video_probe(icd, client); + ret = ov6650_video_probe(client); if (!ret) ret = v4l2_ctrl_handler_setup(&priv->hdl); diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 9b540421e2cb..a2146c30771e 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -953,17 +953,12 @@ static int ov772x_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov772x_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov772x_video_probe(struct i2c_client *client) { struct ov772x_priv *priv = to_ov772x(client); u8 pid, ver; const char *devname; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show product ID and manufacturer ID */ @@ -1021,8 +1016,7 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -1056,20 +1050,15 @@ static struct v4l2_subdev_ops ov772x_subdev_ops = { static int ov772x_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct ov772x_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; - - if (!icd) { - dev_err(&client->dev, "OV772X: missing soc-camera data!\n"); - return -EINVAL; - } + struct ov772x_priv *priv; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) + if (!icl || !icl->priv) { + dev_err(&client->dev, "OV772X: missing platform data!\n"); return -EINVAL; + } if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&adapter->dev, @@ -1100,7 +1089,7 @@ static int ov772x_probe(struct i2c_client *client, return err; } - ret = ov772x_video_probe(icd, client); + ret = ov772x_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&priv->hdl); kfree(priv); diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 12d33a9c07b0..f9babf39d802 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -578,8 +578,7 @@ static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov9640_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov9640_video_probe(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov9640_priv *priv = to_ov9640_sensor(sd); @@ -587,10 +586,6 @@ static int ov9640_video_probe(struct soc_camera_device *icd, const char *devname; int ret = 0; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show product ID and manufacturer ID */ @@ -644,8 +639,7 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -678,16 +672,9 @@ static int ov9640_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov9640_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "Missing platform_data for driver\n"); return -EINVAL; @@ -715,7 +702,7 @@ static int ov9640_probe(struct i2c_client *client, return err; } - ret = ov9640_video_probe(icd, client); + ret = ov9640_video_probe(client); if (ret) { v4l2_ctrl_handler_free(&priv->hdl); diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index 3dd910dcc5b8..9558aca86818 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c @@ -836,18 +836,13 @@ static int ov9740_set_register(struct v4l2_subdev *sd, } #endif -static int ov9740_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int ov9740_video_probe(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov9740_priv *priv = to_ov9740(sd); u8 modelhi, modello; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * check and show product ID and manufacturer ID */ @@ -893,8 +888,7 @@ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -940,16 +934,9 @@ static int ov9740_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov9740_priv *priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); int ret; - if (!icd) { - dev_err(&client->dev, "Missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "Missing platform_data for driver\n"); return -EINVAL; @@ -975,7 +962,7 @@ static int ov9740_probe(struct i2c_client *client, return err; } - ret = ov9740_video_probe(icd, client); + ret = ov9740_video_probe(client); if (!ret) ret = v4l2_ctrl_handler_setup(&priv->hdl); if (ret < 0) { diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 9a871537d233..fcb14d93a24c 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -1235,8 +1235,7 @@ static int rj54n1_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -1252,8 +1251,7 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ if (soc_camera_apply_board_flags(icl, cfg) & @@ -1285,17 +1283,12 @@ static struct v4l2_subdev_ops rj54n1_subdev_ops = { * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int rj54n1_video_probe(struct soc_camera_device *icd, - struct i2c_client *client, +static int rj54n1_video_probe(struct i2c_client *client, struct rj54n1_pdata *priv) { int data1, data2; int ret; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* Read out the chip version register */ data1 = reg_read(client, RJ54N1_DEV_CODE); data2 = reg_read(client, RJ54N1_DEV_CODE2); @@ -1323,18 +1316,11 @@ static int rj54n1_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct rj54n1 *rj54n1; - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; struct rj54n1_pdata *rj54n1_priv; int ret; - if (!icd) { - dev_err(&client->dev, "RJ54N1CB0C: missing soc-camera data!\n"); - return -EINVAL; - } - - icl = to_soc_camera_link(icd); if (!icl || !icl->priv) { dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); return -EINVAL; @@ -1382,7 +1368,7 @@ static int rj54n1_probe(struct i2c_client *client, rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); - ret = rj54n1_video_probe(icd, client, rj54n1_priv); + ret = rj54n1_video_probe(client, rj54n1_priv); if (ret < 0) { v4l2_ctrl_handler_free(&rj54n1->hdl); kfree(rj54n1); @@ -1394,8 +1380,7 @@ static int rj54n1_probe(struct i2c_client *client, static int rj54n1_remove(struct i2c_client *client) { struct rj54n1 *rj54n1 = to_rj54n1(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); v4l2_device_unregister_subdev(&rj54n1->subdev); if (icl->free_bus) diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 2fddd1fbe529..5a3722b756c7 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -764,10 +764,6 @@ static int tw9910_video_probe(struct soc_camera_device *icd, struct tw9910_priv *priv = to_tw9910(client); s32 id; - /* We must have a parent by now. And it cannot be a wrong one. */ - BUG_ON(!icd->parent || - to_soc_camera_host(icd->parent)->nr != icd->iface); - /* * tw9910 only use 8 or 16 bit bus width */ @@ -825,8 +821,7 @@ static int tw9910_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | @@ -842,8 +837,7 @@ static int tw9910_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); u8 val = VSSL_VVALID | HSSL_DVALID; unsigned long flags = soc_camera_apply_board_flags(icl, cfg); @@ -887,23 +881,19 @@ static int tw9910_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct tw9910_priv *priv; - struct tw9910_video_info *info; - struct soc_camera_device *icd = client->dev.platform_data; - struct i2c_adapter *adapter = + struct tw9910_priv *priv; + struct tw9910_video_info *info; + struct soc_camera_device *icd = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; - int ret; + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); + int ret; - if (!icd) { - dev_err(&client->dev, "TW9910: missing soc-camera data!\n"); + if (!icl || !icl->priv) { + dev_err(&client->dev, "TW9910: missing platform data!\n"); return -EINVAL; } - icl = to_soc_camera_link(icd); - if (!icl || !icl->priv) - return -EINVAL; - info = icl->priv; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -921,8 +911,6 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - icd->iface = icl->bus_id; - ret = tw9910_video_probe(icd, client); if (ret) kfree(priv); diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 6398ff0f08ab..67a52c729eff 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -251,18 +251,35 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, /* This is only temporary here - until v4l2-subdev begins to link to video_device */ #include -static inline struct video_device *soc_camera_i2c_to_vdev(struct i2c_client *client) +static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client) { struct soc_camera_device *icd = client->dev.platform_data; - return icd->vdev; + return icd ? icd->vdev : NULL; } -static inline struct soc_camera_device *soc_camera_from_vb2q(struct vb2_queue *vq) +static inline struct soc_camera_link *soc_camera_i2c_to_link(const struct i2c_client *client) +{ + struct soc_camera_device *icd = client->dev.platform_data; + return icd ? to_soc_camera_link(icd) : NULL; +} + +static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_device *vdev) +{ + struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); + return soc_camera_to_subdev(icd); +} + +static inline struct soc_camera_device *soc_camera_from_i2c(const struct i2c_client *client) +{ + return client->dev.platform_data; +} + +static inline struct soc_camera_device *soc_camera_from_vb2q(const struct vb2_queue *vq) { return container_of(vq, struct soc_camera_device, vb2_vidq); } -static inline struct soc_camera_device *soc_camera_from_vbq(struct videobuf_queue *vq) +static inline struct soc_camera_device *soc_camera_from_vbq(const struct videobuf_queue *vq) { return container_of(vq, struct soc_camera_device, vb_vidq); } From 443f483aa2494b93d73ba122cafdf2ef89989ed7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 07:06:50 -0300 Subject: [PATCH 1353/1596] [media] V4L: mt9m001, mt9v022: use internally cached pixel code Using the internally cached pixel code, instead of the one, provided by the soc-camera, removes one more use of struct soc_camera_device in these drivers. Also remove the no longer needed soc_camera_from_i2c() inline function. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 10 ++-------- drivers/media/video/mt9v022.c | 14 ++------------ include/media/soc_camera.h | 5 ----- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 58cdcedf53de..63ae5c61c9bf 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -601,15 +601,9 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { const struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = soc_camera_from_i2c(client); struct soc_camera_link *icl = soc_camera_i2c_to_link(client); - /* - * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that - * is the number of bits, that the host has to sample, not the number of - * bits, that we have to send. See mx3_camera.c for an example of 10-bit - * formats being truncated to 8 bits by the host. - */ - unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample; + struct mt9m001 *mt9m001 = to_mt9m001(client); + unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample; if (icl->set_bus_param) return icl->set_bus_param(icl, 1 << (bps - 1)); diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 72b179b2ad6c..b6a29f7de82c 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -700,23 +700,13 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; - struct soc_camera_link *icl = to_soc_camera_link(icd); + struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct mt9v022 *mt9v022 = to_mt9v022(client); unsigned long flags = soc_camera_apply_board_flags(icl, cfg); - /* - * Cannot use icd->current_fmt->host_fmt->bits_per_sample, because that - * is the number of bits, that the host has to sample, not the number of - * bits, that we have to send. See mx3_camera.c for an example of 10-bit - * formats being truncated to 8 bits by the host. - */ - unsigned int bps = soc_mbus_get_fmtdesc(icd->current_fmt->code)->bits_per_sample; + unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; int ret; u16 pixclk = 0; - dev_dbg(icd->pdev, "set %d: %s, %dbps\n", icd->current_fmt->code, - icd->current_fmt->host_fmt->name, bps); - if (icl->set_bus_param) { ret = icl->set_bus_param(icl, 1 << (bps - 1)); if (ret) diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 67a52c729eff..dac57598ee57 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -269,11 +269,6 @@ static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_d return soc_camera_to_subdev(icd); } -static inline struct soc_camera_device *soc_camera_from_i2c(const struct i2c_client *client) -{ - return client->dev.platform_data; -} - static inline struct soc_camera_device *soc_camera_from_vb2q(const struct vb2_queue *vq) { return container_of(vq, struct soc_camera_device, vb2_vidq); From 2fbdc9bd42c993a6b179a4ddb972b551644aad6e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 06:40:56 -0300 Subject: [PATCH 1354/1596] [media] V4L: sh_mobile_csi2: fix unbalanced pm_runtime_put() If the sh_mobile_csi2 driver didn't attach to a client, normally, because the respective device connects to the SoC over the parallel CEU interface and doesn't use the CSI-2 controller, it also shouldn't call pm_runtime_put() on attempted disconnect. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_csi2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 91c680a72849..37706eb81f25 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -208,6 +208,9 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) unsigned long common_flags, csi2_flags; int i, ret; + if (priv->client) + return -EBUSY; + for (i = 0; i < pdata->num_clients; i++) if (&pdata->clients[i].pdev->dev == icd->pdev) break; @@ -262,6 +265,9 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) static void sh_csi2_client_disconnect(struct sh_csi2 *priv) { + if (!priv->client) + return; + priv->client = NULL; pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); From 3e0ec41c5c5ee14e27f65e28d4a616de34f59a97 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 13 Sep 2011 08:07:55 -0300 Subject: [PATCH 1355/1596] [media] V4L: dynamically allocate video_device nodes in subdevices Currently only very few drivers actually use video_device nodes, embedded in struct v4l2_subdev. Allocate these nodes dynamically for those drivers to save memory for the rest. Signed-off-by: Guennadi Liakhovetski Tested-by: Sylwester Nawrocki Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-device.c | 36 ++++++++++++++++++++++++++----- include/media/v4l2-subdev.h | 4 ++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index e6a2c3b302d4..9fc0ae8a526a 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -21,6 +21,7 @@ #include #include #include +#include #if defined(CONFIG_SPI) #include #endif @@ -193,6 +194,13 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); +static void v4l2_device_release_subdev_node(struct video_device *vdev) +{ + struct v4l2_subdev *sd = video_get_drvdata(vdev); + sd->devnode = NULL; + kfree(vdev); +} + int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) { struct video_device *vdev; @@ -206,22 +214,40 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) continue; - vdev = &sd->devnode; + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + if (!vdev) { + err = -ENOMEM; + goto clean_up; + } + + video_set_drvdata(vdev, sd); strlcpy(vdev->name, sd->name, sizeof(vdev->name)); vdev->v4l2_dev = v4l2_dev; vdev->fops = &v4l2_subdev_fops; - vdev->release = video_device_release_empty; + vdev->release = v4l2_device_release_subdev_node; vdev->ctrl_handler = sd->ctrl_handler; err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, sd->owner); - if (err < 0) - return err; + if (err < 0) { + kfree(vdev); + goto clean_up; + } #if defined(CONFIG_MEDIA_CONTROLLER) sd->entity.v4l.major = VIDEO_MAJOR; sd->entity.v4l.minor = vdev->minor; #endif + sd->devnode = vdev; } return 0; + +clean_up: + list_for_each_entry(sd, &v4l2_dev->subdevs, list) { + if (!sd->devnode) + break; + video_unregister_device(sd->devnode); + } + + return err; } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); @@ -247,7 +273,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) if (v4l2_dev->mdev) media_device_unregister_entity(&sd->entity); #endif - video_unregister_device(&sd->devnode); + video_unregister_device(sd->devnode); module_put(sd->owner); } EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 257da1a30f66..5dd049a7437d 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -534,13 +534,13 @@ struct v4l2_subdev { void *dev_priv; void *host_priv; /* subdev device node */ - struct video_device devnode; + struct video_device *devnode; }; #define media_entity_to_v4l2_subdev(ent) \ container_of(ent, struct v4l2_subdev, entity) #define vdev_to_v4l2_subdev(vdev) \ - container_of(vdev, struct v4l2_subdev, devnode) + video_get_drvdata(vdev) /* * Used for storing subdev information per file handle From 1a99b972a86ba9c3984c042f7f641458ad4812d0 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 13:10:02 -0300 Subject: [PATCH 1356/1596] [media] V4L: add .g_std() core V4L2 subdevice operation VIDIOC_G_STD can return the current TV-norm to the user in one of two ways: if an .vidioc_g_std() ioctl operation is provided by the driver, it is called, otherwise the value ot the .current_norm field of struct video_device is returned. Since subdevice drivers currently have no access to struct video_device objects, the only way to provide this information to the user is by implementing a .g_std() method. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5dd049a7437d..f0f3358d1b1b 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -158,6 +158,7 @@ struct v4l2_subdev_core_ops { int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm); + int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm); int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); #ifdef CONFIG_VIDEO_ADV_DEBUG From 2f0babb7e43278247df512263581c4738afa4cbc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 13:39:20 -0300 Subject: [PATCH 1357/1596] [media] V4L: soc-camera: make (almost) all client drivers re-usable outside of the framework The most important change in this patch is direct linking to struct soc_camera_link via the client->dev.platform_data pointer. This makes most of the soc-camera client drivers also usable outside of the soc-camera framework. After this change all what is needed for these drivers to function are inclusions of soc-camera headers for some convenience macros, suitably configured platform data, which is anyway always required, and loaded soc-camera core module for library functions. If desired, these library functions can be made generic in the future and moved to a more neutral location. The only two client drivers, that still depend on soc-camera are: mt9t031: it uses struct video_device for its PM. Since no hardware is available, alternative methods cannot be tested. ov6650: it uses struct soc_camera_device to pass its sense data back to the bridge driver. A generic v4l2-subdevice approach should be developed to perform this. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9t031.c | 29 ++++++++++++++---- drivers/media/video/ov6650.c | 2 +- drivers/media/video/soc_camera.c | 11 ++++++- drivers/media/video/tw9910.c | 50 +++++++++++++++++++------------- include/media/soc_camera.h | 6 ++-- 5 files changed, 68 insertions(+), 30 deletions(-) diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 95cd602ae4ec..0226486d59be 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -21,6 +21,13 @@ #include #include +/* + * ATTENTION: this driver still cannot be used outside of the soc-camera + * framework because of its PM implementation, using the video_device node. + * If hardware becomes available for testing, alternative PM approaches shall + * be considered and tested. + */ + /* * mt9t031 i2c address 0x5d * The platform has to define i2c_board_info and link to it from @@ -606,6 +613,19 @@ static struct device_type mt9t031_dev_type = { .pm = &mt9t031_dev_pm_ops, }; +static int mt9t031_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct video_device *vdev = soc_camera_i2c_to_vdev(client); + + if (on) + vdev->dev.type = &mt9t031_dev_type; + else + vdev->dev.type = NULL; + + return 0; +} + /* * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one @@ -613,7 +633,6 @@ static struct device_type mt9t031_dev_type = { static int mt9t031_video_probe(struct i2c_client *client) { struct mt9t031 *mt9t031 = to_mt9t031(client); - struct video_device *vdev = soc_camera_i2c_to_vdev(client); s32 data; int ret; @@ -637,12 +656,11 @@ static int mt9t031_video_probe(struct i2c_client *client) dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); ret = mt9t031_idle(client); - if (ret < 0) { + if (ret < 0) dev_err(&client->dev, "Failed to initialise the camera\n"); - } else { - vdev->dev.type = &mt9t031_dev_type; + else v4l2_ctrl_handler_setup(&mt9t031->hdl); - } + return ret; } @@ -663,6 +681,7 @@ static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { .g_chip_ident = mt9t031_g_chip_ident, + .s_power = mt9t031_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9t031_g_register, .s_register = mt9t031_s_register, diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index f060eaaf916f..eb296f9e69f4 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -541,7 +541,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe, static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; struct soc_camera_sense *sense = icd->sense; struct ov6650 *priv = to_ov6650(client); bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 9a62ed08d86a..b72580c38957 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -249,6 +249,14 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) return v4l2_subdev_call(sd, core, s_std, *a); } +static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) +{ + struct soc_camera_device *icd = file->private_data; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + + return v4l2_subdev_call(sd, core, g_std, a); +} + static int soc_camera_enum_fsizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { @@ -977,7 +985,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, goto ei2cga; } - icl->board_info->platform_data = icd; + icl->board_info->platform_data = icl; subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, icl->board_info, NULL); @@ -1376,6 +1384,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_g_input = soc_camera_g_input, .vidioc_s_input = soc_camera_s_input, .vidioc_s_std = soc_camera_s_std, + .vidioc_g_std = soc_camera_g_std, .vidioc_enum_framesizes = soc_camera_enum_fsizes, .vidioc_reqbufs = soc_camera_reqbufs, .vidioc_querybuf = soc_camera_querybuf, diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 5a3722b756c7..efce5371915e 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -230,6 +230,7 @@ struct tw9910_priv { struct v4l2_subdev subdev; struct tw9910_video_info *info; const struct tw9910_scale_ctrl *scale; + v4l2_std_id norm; u32 revision; }; @@ -421,12 +422,11 @@ static int tw9910_power(struct i2c_client *client, int enable) return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); } -static const struct tw9910_scale_ctrl *tw9910_select_norm(struct soc_camera_device *icd, +static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm, u32 width, u32 height) { const struct tw9910_scale_ctrl *scale; const struct tw9910_scale_ctrl *ret = NULL; - v4l2_std_id norm = icd->vdev->current_norm; __u32 diff = 0xffffffff, tmp; int size, i; @@ -495,14 +495,27 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) return tw9910_power(client, enable); } +static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); + + *norm = priv->norm; + + return 0; +} + static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) { - int ret = -EINVAL; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct tw9910_priv *priv = to_tw9910(client); - if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL)) - ret = 0; + if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL))) + return -EINVAL; - return ret; + priv->norm = norm; + + return 0; } static int tw9910_g_chip_ident(struct v4l2_subdev *sd, @@ -557,14 +570,13 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); - struct soc_camera_device *icd = client->dev.platform_data; int ret = -EINVAL; u8 val; /* * select suitable norm */ - priv->scale = tw9910_select_norm(icd, *width, *height); + priv->scale = tw9910_select_norm(priv->norm, *width, *height); if (!priv->scale) goto tw9910_set_fmt_error; @@ -642,11 +654,11 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; + struct tw9910_priv *priv = to_tw9910(client); a->c.left = 0; a->c.top = 0; - if (icd->vdev->current_norm & V4L2_STD_NTSC) { + if (priv->norm & V4L2_STD_NTSC) { a->c.width = 640; a->c.height = 480; } else { @@ -661,11 +673,11 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; + struct tw9910_priv *priv = to_tw9910(client); a->bounds.left = 0; a->bounds.top = 0; - if (icd->vdev->current_norm & V4L2_STD_NTSC) { + if (priv->norm & V4L2_STD_NTSC) { a->bounds.width = 640; a->bounds.height = 480; } else { @@ -732,7 +744,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = client->dev.platform_data; + struct tw9910_priv *priv = to_tw9910(client); const struct tw9910_scale_ctrl *scale; if (V4L2_FIELD_ANY == mf->field) { @@ -748,7 +760,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, /* * select suitable norm */ - scale = tw9910_select_norm(icd, mf->width, mf->height); + scale = tw9910_select_norm(priv->norm, mf->width, mf->height); if (!scale) return -EINVAL; @@ -758,8 +770,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, return 0; } -static int tw9910_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) +static int tw9910_video_probe(struct i2c_client *client) { struct tw9910_priv *priv = to_tw9910(client); s32 id; @@ -792,8 +803,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd, dev_info(&client->dev, "tw9910 Product ID %0x:%0x\n", id, priv->revision); - icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; - icd->vdev->current_norm = V4L2_STD_NTSC; + priv->norm = V4L2_STD_NTSC; return 0; } @@ -801,6 +811,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd, static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { .g_chip_ident = tw9910_g_chip_ident, .s_std = tw9910_s_std, + .g_std = tw9910_g_std, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = tw9910_g_register, .s_register = tw9910_s_register, @@ -883,7 +894,6 @@ static int tw9910_probe(struct i2c_client *client, { struct tw9910_priv *priv; struct tw9910_video_info *info; - struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct soc_camera_link *icl = soc_camera_i2c_to_link(client); @@ -911,7 +921,7 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - ret = tw9910_video_probe(icd, client); + ret = tw9910_video_probe(client); if (ret) kfree(priv); diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index dac57598ee57..b1377b931eb7 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -253,14 +253,14 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, #include static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client) { - struct soc_camera_device *icd = client->dev.platform_data; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; return icd ? icd->vdev : NULL; } static inline struct soc_camera_link *soc_camera_i2c_to_link(const struct i2c_client *client) { - struct soc_camera_device *icd = client->dev.platform_data; - return icd ? to_soc_camera_link(icd) : NULL; + return client->dev.platform_data; } static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_device *vdev) From 95d20109ad6478ecea5e93ba191270fb645d52c7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 9 Sep 2011 13:56:04 -0300 Subject: [PATCH 1358/1596] [media] V4L: replace soc-camera specific soc_mediabus.h with v4l2-mediabus.h Most users of the header only need pixel code definitions, which are now located in the generic header. Switch over to reduce soc-camera dependencies. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 2 +- drivers/media/video/mt9m111.c | 2 +- drivers/media/video/mt9t031.c | 2 +- drivers/media/video/mt9t112.c | 2 +- drivers/media/video/ov2640.c | 2 +- drivers/media/video/ov5642.c | 2 +- drivers/media/video/ov6650.c | 2 +- drivers/media/video/ov772x.c | 2 +- drivers/media/video/ov9640.c | 2 +- drivers/media/video/ov9740.c | 2 +- drivers/media/video/rj54n1cb0c.c | 2 +- drivers/media/video/tw9910.c | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 4f3ce7fa87df..8775e262bb6e 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -12,11 +12,11 @@ #include #include +#include #include #include #include -#include #include #include diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 9feeb0cb6722..f023cc092c2b 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -13,9 +13,9 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 0226486d59be..7ee84cc578b9 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -13,10 +13,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 5b045a1097c6..32114a3c0ca7 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -22,11 +22,11 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index d37a5cceebb6..b5247cb64fde 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -18,10 +18,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 2a26602fc86d..54178cbeabb4 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -19,9 +19,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index eb296f9e69f4..8d17c519a9f7 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -28,9 +28,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index a2146c30771e..9f6ce3d8a29e 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -20,11 +20,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index f9babf39d802..a4f99797eb56 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -24,10 +24,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index 9558aca86818..d9a9f7174f7a 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c @@ -14,9 +14,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index fcb14d93a24c..6afc61689549 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -11,11 +11,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index efce5371915e..a514fa61116c 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -22,10 +22,10 @@ #include #include #include +#include #include #include -#include #include #include #include From 171f1a48bb3f95e3ecb37ecd6e8577118d601460 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Thu, 8 Sep 2011 13:15:24 -0300 Subject: [PATCH 1359/1596] [media] media: ov5642: Add support for arbitrary resolution This patch adds the ability to get arbitrary resolutions with a width up to 2592 and a height up to 720 pixels instead of the standard 1280x720 only. Signed-off-by: Bastian Hecht Acked-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov5642.c | 240 ++++++++++++++++++++++++----------- 1 file changed, 167 insertions(+), 73 deletions(-) diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 54178cbeabb4..bb37ec80f274 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c @@ -14,8 +14,10 @@ * published by the Free Software Foundation. */ +#include #include #include +#include #include #include #include @@ -35,7 +37,7 @@ #define REG_WINDOW_START_Y_LOW 0x3803 #define REG_WINDOW_WIDTH_HIGH 0x3804 #define REG_WINDOW_WIDTH_LOW 0x3805 -#define REG_WINDOW_HEIGHT_HIGH 0x3806 +#define REG_WINDOW_HEIGHT_HIGH 0x3806 #define REG_WINDOW_HEIGHT_LOW 0x3807 #define REG_OUT_WIDTH_HIGH 0x3808 #define REG_OUT_WIDTH_LOW 0x3809 @@ -45,19 +47,44 @@ #define REG_OUT_TOTAL_WIDTH_LOW 0x380d #define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e #define REG_OUT_TOTAL_HEIGHT_LOW 0x380f +#define REG_OUTPUT_FORMAT 0x4300 +#define REG_ISP_CTRL_01 0x5001 +#define REG_AVG_WINDOW_END_X_HIGH 0x5682 +#define REG_AVG_WINDOW_END_X_LOW 0x5683 +#define REG_AVG_WINDOW_END_Y_HIGH 0x5686 +#define REG_AVG_WINDOW_END_Y_LOW 0x5687 + +/* active pixel array size */ +#define OV5642_SENSOR_SIZE_X 2592 +#define OV5642_SENSOR_SIZE_Y 1944 /* - * define standard resolution. - * Works currently only for up to 720 lines - * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720 + * About OV5642 resolution, cropping and binning: + * This sensor supports it all, at least in the feature description. + * Unfortunately, no combination of appropriate registers settings could make + * the chip work the intended way. As it works with predefined register lists, + * some undocumented registers are presumably changed there to achieve their + * goals. + * This driver currently only works for resolutions up to 720 lines with a + * 1:1 scale. Hopefully these restrictions will be removed in the future. */ +#define OV5642_MAX_WIDTH OV5642_SENSOR_SIZE_X +#define OV5642_MAX_HEIGHT 720 -#define OV5642_WIDTH 1280 -#define OV5642_HEIGHT 720 -#define OV5642_TOTAL_WIDTH 3200 -#define OV5642_TOTAL_HEIGHT 2000 -#define OV5642_SENSOR_SIZE_X 2592 -#define OV5642_SENSOR_SIZE_Y 1944 +/* default sizes */ +#define OV5642_DEFAULT_WIDTH 1280 +#define OV5642_DEFAULT_HEIGHT OV5642_MAX_HEIGHT + +/* minimum extra blanking */ +#define BLANKING_EXTRA_WIDTH 500 +#define BLANKING_EXTRA_HEIGHT 20 + +/* + * the sensor's autoexposure is buggy when setting total_height low. + * It tries to expose longer than 1 frame period without taking care of it + * and this leads to weird output. So we set 1000 lines as minimum. + */ +#define BLANKING_MIN_HEIGHT 1000 struct regval_list { u16 reg_num; @@ -582,6 +609,11 @@ struct ov5642_datafmt { struct ov5642 { struct v4l2_subdev subdev; const struct ov5642_datafmt *fmt; + struct v4l2_rect crop_rect; + + /* blanking information */ + int total_width; + int total_height; }; static const struct ov5642_datafmt ov5642_colour_fmts[] = { @@ -642,6 +674,21 @@ static int reg_write(struct i2c_client *client, u16 reg, u8 val) return 0; } + +/* + * convenience function to write 16 bit register values that are split up + * into two consecutive high and low parts + */ +static int reg_write16(struct i2c_client *client, u16 reg, u16 val16) +{ + int ret; + + ret = reg_write(client, reg, val16 >> 8); + if (ret) + return ret; + return reg_write(client, reg + 1, val16 & 0x00ff); +} + #ifdef CONFIG_VIDEO_ADV_DEBUG static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { @@ -685,58 +732,55 @@ static int ov5642_write_array(struct i2c_client *client, return 0; } -static int ov5642_set_resolution(struct i2c_client *client) +static int ov5642_set_resolution(struct v4l2_subdev *sd) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5642 *priv = to_ov5642(client); + int width = priv->crop_rect.width; + int height = priv->crop_rect.height; + int total_width = priv->total_width; + int total_height = priv->total_height; + int start_x = (OV5642_SENSOR_SIZE_X - width) / 2; + int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2; int ret; - u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8; - u8 start_x_low = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff; - u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8; - u8 start_y_low = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff; - - u8 width_high = OV5642_WIDTH >> 8; - u8 width_low = OV5642_WIDTH & 0xff; - u8 height_high = OV5642_HEIGHT >> 8; - u8 height_low = OV5642_HEIGHT & 0xff; - - u8 total_width_high = OV5642_TOTAL_WIDTH >> 8; - u8 total_width_low = OV5642_TOTAL_WIDTH & 0xff; - u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8; - u8 total_height_low = OV5642_TOTAL_HEIGHT & 0xff; - - ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high); - if (!ret) - ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low); - if (!ret) - ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high); - if (!ret) - ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low); + /* + * This should set the starting point for cropping. + * Doesn't work so far. + */ + ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x); if (!ret) - ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high); - if (!ret) - ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low); - if (!ret) - ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high); - if (!ret) - ret = reg_write(client, REG_WINDOW_HEIGHT_LOW, height_low); + ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y); + if (!ret) { + priv->crop_rect.left = start_x; + priv->crop_rect.top = start_y; + } if (!ret) - ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high); + ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width); if (!ret) - ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low); - if (!ret) - ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high); + ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height); + if (ret) + return ret; + priv->crop_rect.width = width; + priv->crop_rect.height = height; + + /* Set the output window size. Only 1:1 scale is supported so far. */ + ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width); if (!ret) - ret = reg_write(client, REG_OUT_HEIGHT_LOW, height_low); + ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height); + /* Total width = output size + blanking */ if (!ret) - ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high); + ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width); if (!ret) - ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low); + ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height); + + /* Sets the window for AWB calculations */ if (!ret) - ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high); + ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width); if (!ret) - ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW, total_height_low); + ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height); return ret; } @@ -744,18 +788,18 @@ static int ov5642_set_resolution(struct i2c_client *client) static int ov5642_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5642 *priv = to_ov5642(client); const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); - dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n", - __func__, mf->code, mf->width, mf->height); + mf->width = priv->crop_rect.width; + mf->height = priv->crop_rect.height; if (!fmt) { mf->code = ov5642_colour_fmts[0].code; mf->colorspace = ov5642_colour_fmts[0].colorspace; } - mf->width = OV5642_WIDTH; - mf->height = OV5642_HEIGHT; mf->field = V4L2_FIELD_NONE; return 0; @@ -767,20 +811,13 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5642 *priv = to_ov5642(client); - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); - /* MIPI CSI could have changed the format, double-check */ if (!ov5642_find_datafmt(mf->code)) return -EINVAL; ov5642_try_fmt(sd, mf); - priv->fmt = ov5642_find_datafmt(mf->code); - ov5642_write_array(client, ov5642_default_regs_init); - ov5642_set_resolution(client); - ov5642_write_array(client, ov5642_default_regs_finalise); - return 0; } @@ -794,8 +831,8 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd, mf->code = fmt->code; mf->colorspace = fmt->colorspace; - mf->width = OV5642_WIDTH; - mf->height = OV5642_HEIGHT; + mf->width = priv->crop_rect.width; + mf->height = priv->crop_rect.height; mf->field = V4L2_FIELD_NONE; return 0; @@ -828,15 +865,44 @@ static int ov5642_g_chip_ident(struct v4l2_subdev *sd, return 0; } +static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5642 *priv = to_ov5642(client); + struct v4l2_rect *rect = &a->c; + int ret; + + v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1, + &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0); + + priv->crop_rect.width = rect->width; + priv->crop_rect.height = rect->height; + priv->total_width = rect->width + BLANKING_EXTRA_WIDTH; + priv->total_height = max_t(int, rect->height + + BLANKING_EXTRA_HEIGHT, + BLANKING_MIN_HEIGHT); + priv->crop_rect.width = rect->width; + priv->crop_rect.height = rect->height; + + ret = ov5642_write_array(client, ov5642_default_regs_init); + if (!ret) + ret = ov5642_set_resolution(sd); + if (!ret) + ret = ov5642_write_array(client, ov5642_default_regs_finalise); + + return ret; +} + static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5642 *priv = to_ov5642(client); struct v4l2_rect *rect = &a->c; - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - rect->top = 0; - rect->left = 0; - rect->width = OV5642_WIDTH; - rect->height = OV5642_HEIGHT; + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + *rect = priv->crop_rect; return 0; } @@ -845,8 +911,8 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) { a->bounds.left = 0; a->bounds.top = 0; - a->bounds.width = OV5642_WIDTH; - a->bounds.height = OV5642_HEIGHT; + a->bounds.width = OV5642_MAX_WIDTH; + a->bounds.height = OV5642_MAX_HEIGHT; a->defrect = a->bounds; a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; a->pixelaspect.numerator = 1; @@ -859,24 +925,43 @@ static int ov5642_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { cfg->type = V4L2_MBUS_CSI2; - cfg->flags = V4L2_MBUS_CSI2_2_LANE | - V4L2_MBUS_CSI2_CHANNEL_0 | - V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; return 0; } +static int ov5642_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client; + int ret; + + if (!on) + return 0; + + client = v4l2_get_subdevdata(sd); + ret = ov5642_write_array(client, ov5642_default_regs_init); + if (!ret) + ret = ov5642_set_resolution(sd); + if (!ret) + ret = ov5642_write_array(client, ov5642_default_regs_finalise); + + return ret; +} + static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { .s_mbus_fmt = ov5642_s_fmt, .g_mbus_fmt = ov5642_g_fmt, .try_mbus_fmt = ov5642_try_fmt, .enum_mbus_fmt = ov5642_enum_fmt, + .s_crop = ov5642_s_crop, .g_crop = ov5642_g_crop, .cropcap = ov5642_cropcap, .g_mbus_config = ov5642_g_mbus_config, }; static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { + .s_power = ov5642_s_power, .g_chip_ident = ov5642_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov5642_get_register, @@ -934,7 +1019,16 @@ static int ov5642_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); - priv->fmt = &ov5642_colour_fmts[0]; + priv->fmt = &ov5642_colour_fmts[0]; + + priv->crop_rect.width = OV5642_DEFAULT_WIDTH; + priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; + priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2; + priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2; + priv->crop_rect.width = OV5642_DEFAULT_WIDTH; + priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; + priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; + priv->total_height = BLANKING_MIN_HEIGHT; ret = ov5642_video_probe(client); if (ret < 0) From 2e56d933fd967a72d5ee4250e1cb6f9de29d936f Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 12 Sep 2011 08:25:25 -0300 Subject: [PATCH 1360/1596] [media] media: ov6650: stylistic improvements * with no "retrun ret;" at the end, there is no need to initialize ret any longer, * consequently use conditional expressions, not if...else constructs, throughout ov6650_s_ctrl(), * v4l2_ctrl_new_std_menu() max value of V4L2_EXPOSURE_MANUAL instead of equivalent 1 looks more clear. Created on top of "Converting soc_camera to the control framework" series. Signed-off-by: Janusz Krzysztofik Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ov6650.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 8d17c519a9f7..d5b057207a7b 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -310,7 +310,7 @@ static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); uint8_t reg, reg2; - int ret = 0; + int ret; switch (ctrl->id) { case V4L2_CID_AUTOGAIN: @@ -342,7 +342,7 @@ static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); struct v4l2_subdev *sd = &priv->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; + int ret; switch (ctrl->id) { case V4L2_CID_AUTOGAIN: @@ -370,10 +370,8 @@ static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_BRIGHTNESS: return ov6650_reg_write(client, REG_BRT, ctrl->val); case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->val == V4L2_EXPOSURE_AUTO) - ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); - else - ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); + ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val == + V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC); if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) ret = ov6650_reg_write(client, REG_AECH, priv->exposure->val); @@ -983,8 +981,8 @@ static int ov6650_probe(struct i2c_client *client, v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, - &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, - V4L2_EXPOSURE_AUTO); + &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, From d26a6635b24210791cf4b71fd861738270c8cc3c Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sun, 4 Sep 2011 19:08:54 -0300 Subject: [PATCH 1361/1596] [media] v4l: Add AUTO option for the V4L2_CID_POWER_LINE_FREQUENCY control V4L2_CID_POWER_LINE_FREQUENCY control allows applications to instruct a driver what is the power line frequency so an appropriate filter can be used by the device to cancel flicker by compensating the light intensity ripple. Currently in the menu we have entries for 50 Hz and 60 Hz and for entirely disabling the anti-flicker filter. However some devices are capable of automatically detecting the frequency, so add V4L2_CID_POWER_LINE_FREQUENCY_AUTO entry for them. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 5 +++-- drivers/media/video/v4l2-ctrls.c | 1 + include/linux/videodev2.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 23fdf79f8cf3..3bc5ee8b2c74 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -232,8 +232,9 @@ control is deprecated. New drivers and applications should use the Enables a power line frequency filter to avoid flicker. Possible values for enum v4l2_power_line_frequency are: V4L2_CID_POWER_LINE_FREQUENCY_DISABLED (0), -V4L2_CID_POWER_LINE_FREQUENCY_50HZ (1) and -V4L2_CID_POWER_LINE_FREQUENCY_60HZ (2). +V4L2_CID_POWER_LINE_FREQUENCY_50HZ (1), +V4L2_CID_POWER_LINE_FREQUENCY_60HZ (2) and +V4L2_CID_POWER_LINE_FREQUENCY_AUTO (3). V4L2_CID_HUE_AUTO diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index fc8666ae408f..5552f8137571 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -210,6 +210,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Disabled", "50 Hz", "60 Hz", + "Auto", NULL }; static const char * const camera_exposure_auto[] = { diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 66945a6f628d..4b752d5ee80e 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1169,6 +1169,7 @@ enum v4l2_power_line_frequency { V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO = 3, }; #define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) #define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) From bfa8dd3a05248457fce18712e7bc0499030b3100 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 4 Oct 2011 14:05:58 -0300 Subject: [PATCH 1362/1596] [media] v4l: Add v4l2 subdev driver for S5K6AAFX sensor This driver exposes preview mode operation of the S5K6AAFX sensor with embedded SoC ISP. The native capture (snapshot) operation mode is not supported. Following controls are available: manual/auto exposure and gain, power line frequency (anti-flicker), saturation, sharpness, brightness, contrast, white balance temperature, color effects, horizontal/vertical image flip, frame interval, auto white balance. RGB component gains are currently exposed through private controls. Reviewed-by: Sakari Ailus Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 7 + drivers/media/video/Makefile | 1 + drivers/media/video/s5k6aa.c | 1680 ++++++++++++++++++++++++++++++++++ include/media/s5k6aa.h | 51 ++ 4 files changed, 1739 insertions(+) create mode 100644 drivers/media/video/s5k6aa.c create mode 100644 include/media/s5k6aa.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d471d1e5a744..b303a3f8a9f8 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -517,6 +517,13 @@ config VIDEO_NOON010PC30 source "drivers/media/video/m5mols/Kconfig" +config VIDEO_S5K6AA + tristate "Samsung S5K6AAFX sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + ---help--- + This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M + camera sensor with an embedded SoC image signal processor. + comment "Flash devices" config VIDEO_ADP1653 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index faba1e333110..117f9c4b4cb9 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ +obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c new file mode 100644 index 000000000000..2446736b7871 --- /dev/null +++ b/drivers/media/video/s5k6aa.c @@ -0,0 +1,1680 @@ +/* + * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor + * with embedded SoC ISP. + * + * Copyright (C) 2011, Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * Based on a driver authored by Dongsoo Nathaniel Kim. + * Copyright (C) 2009, Dongsoo Nathaniel Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, 0644); + +#define DRIVER_NAME "S5K6AA" + +/* The token to indicate array termination */ +#define S5K6AA_TERM 0xffff +#define S5K6AA_OUT_WIDTH_DEF 640 +#define S5K6AA_OUT_HEIGHT_DEF 480 +#define S5K6AA_WIN_WIDTH_MAX 1280 +#define S5K6AA_WIN_HEIGHT_MAX 1024 +#define S5K6AA_WIN_WIDTH_MIN 8 +#define S5K6AA_WIN_HEIGHT_MIN 8 + +/* + * H/W register Interface (0xD0000000 - 0xD0000FFF) + */ +#define AHB_MSB_ADDR_PTR 0xfcfc +#define GEN_REG_OFFSH 0xd000 +#define REG_CMDWR_ADDRH 0x0028 +#define REG_CMDWR_ADDRL 0x002a +#define REG_CMDRD_ADDRH 0x002c +#define REG_CMDRD_ADDRL 0x002e +#define REG_CMDBUF0_ADDR 0x0f12 +#define REG_CMDBUF1_ADDR 0x0f10 + +/* + * Host S/W Register interface (0x70000000 - 0x70002000) + * The value of the two most significant address bytes is 0x7000, + * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs. + */ +#define HOST_SWIF_OFFSH 0x7000 + +/* Initialization parameters */ +/* Master clock frequency in KHz */ +#define REG_I_INCLK_FREQ_L 0x01b8 +#define REG_I_INCLK_FREQ_H 0x01ba +#define MIN_MCLK_FREQ_KHZ 6000U +#define MAX_MCLK_FREQ_KHZ 27000U +#define REG_I_USE_NPVI_CLOCKS 0x01c6 +#define REG_I_USE_NMIPI_CLOCKS 0x01c8 + +/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */ +#define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc) +#define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce) +#define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0) +#define SYS_PLL_OUT_FREQ (48000000 / 4000) +#define PCLK_FREQ_MIN (24000000 / 4000) +#define PCLK_FREQ_MAX (48000000 / 4000) +#define REG_I_INIT_PARAMS_UPDATED 0x01e0 +#define REG_I_ERROR_INFO 0x01e2 + +/* General purpose parameters */ +#define REG_USER_BRIGHTNESS 0x01e4 +#define REG_USER_CONTRAST 0x01e6 +#define REG_USER_SATURATION 0x01e8 +#define REG_USER_SHARPBLUR 0x01ea + +#define REG_G_SPEC_EFFECTS 0x01ee +#define REG_G_ENABLE_PREV 0x01f0 +#define REG_G_ENABLE_PREV_CHG 0x01f2 +#define REG_G_NEW_CFG_SYNC 0x01f8 +#define REG_G_PREVZOOM_IN_WIDTH 0x020a +#define REG_G_PREVZOOM_IN_HEIGHT 0x020c +#define REG_G_PREVZOOM_IN_XOFFS 0x020e +#define REG_G_PREVZOOM_IN_YOFFS 0x0210 +#define REG_G_INPUTS_CHANGE_REQ 0x021a +#define REG_G_ACTIVE_PREV_CFG 0x021c +#define REG_G_PREV_CFG_CHG 0x021e +#define REG_G_PREV_OPEN_AFTER_CH 0x0220 +#define REG_G_PREV_CFG_ERROR 0x0222 + +/* Preview control section. n = 0...4. */ +#define PREG(n, x) ((n) * 0x26 + x) +#define REG_P_OUT_WIDTH(n) PREG(n, 0x0242) +#define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244) +#define REG_P_FMT(n) PREG(n, 0x0246) +#define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248) +#define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a) +#define REG_P_PVI_MASK(n) PREG(n, 0x024c) +#define REG_P_CLK_INDEX(n) PREG(n, 0x024e) +#define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250) +#define FR_RATE_DYNAMIC 0 +#define FR_RATE_FIXED 1 +#define FR_RATE_FIXED_ACCURATE 2 +#define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252) +#define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */ +#define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */ +/* Frame period in 0.1 ms units */ +#define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254) +#define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256) +/* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */ +#define US_TO_FR_TIME(__t) ((__t) / 100) +#define S5K6AA_MIN_FR_TIME 33300 /* us */ +#define S5K6AA_MAX_FR_TIME 650000 /* us */ +#define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */ +/* The below 5 registers are for "device correction" values */ +#define REG_P_COLORTEMP(n) PREG(n, 0x025e) +#define REG_P_PREV_MIRROR(n) PREG(n, 0x0262) + +/* Extended image property controls */ +/* Exposure time in 10 us units */ +#define REG_SF_USR_EXPOSURE_L 0x03c6 +#define REG_SF_USR_EXPOSURE_H 0x03c8 +#define REG_SF_USR_EXPOSURE_CHG 0x03ca +#define REG_SF_USR_TOT_GAIN 0x03cc +#define REG_SF_USR_TOT_GAIN_CHG 0x03ce +#define REG_SF_RGAIN 0x03d0 +#define REG_SF_RGAIN_CHG 0x03d2 +#define REG_SF_GGAIN 0x03d4 +#define REG_SF_GGAIN_CHG 0x03d6 +#define REG_SF_BGAIN 0x03d8 +#define REG_SF_BGAIN_CHG 0x03da +#define REG_SF_FLICKER_QUANT 0x03dc +#define REG_SF_FLICKER_QUANT_CHG 0x03de + +/* Output interface (parallel/MIPI) setup */ +#define REG_OIF_EN_MIPI_LANES 0x03fa +#define REG_OIF_EN_PACKETS 0x03fc +#define REG_OIF_CFG_CHG 0x03fe + +/* Auto-algorithms enable mask */ +#define REG_DBG_AUTOALG_EN 0x0400 +#define AALG_ALL_EN_MASK (1 << 0) +#define AALG_AE_EN_MASK (1 << 1) +#define AALG_DIVLEI_EN_MASK (1 << 2) +#define AALG_WB_EN_MASK (1 << 3) +#define AALG_FLICKER_EN_MASK (1 << 5) +#define AALG_FIT_EN_MASK (1 << 6) +#define AALG_WRHW_EN_MASK (1 << 7) + +/* Firmware revision information */ +#define REG_FW_APIVER 0x012e +#define S5K6AAFX_FW_APIVER 0x0001 +#define REG_FW_REVISION 0x0130 + +/* For now we use only one user configuration register set */ +#define S5K6AA_MAX_PRESETS 1 + +static const char * const s5k6aa_supply_names[] = { + "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */ + "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */ + "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V) + or 2.8V (2.6V to 3.0) */ + "vddio", /* I/O supply 1.8V (1.65V to 1.95V) + or 2.8V (2.5V to 3.1V) */ +}; +#define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names) + +enum s5k6aa_gpio_id { + STBY, + RST, + GPIO_NUM, +}; + +struct s5k6aa_regval { + u16 addr; + u16 val; +}; + +struct s5k6aa_pixfmt { + enum v4l2_mbus_pixelcode code; + u32 colorspace; + /* REG_P_FMT(x) register value */ + u16 reg_p_fmt; +}; + +struct s5k6aa_preset { + /* output pixel format and resolution */ + struct v4l2_mbus_framefmt mbus_fmt; + u8 clk_id; + u8 index; +}; + +struct s5k6aa_ctrls { + struct v4l2_ctrl_handler handler; + /* Auto / manual white balance cluster */ + struct v4l2_ctrl *awb; + struct v4l2_ctrl *gain_red; + struct v4l2_ctrl *gain_blue; + struct v4l2_ctrl *gain_green; + /* Mirror cluster */ + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + /* Auto exposure / manual exposure and gain cluster */ + struct v4l2_ctrl *auto_exp; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; +}; + +struct s5k6aa_interval { + u16 reg_fr_time; + struct v4l2_fract interval; + /* Maximum rectangle for the interval */ + struct v4l2_frmsize_discrete size; +}; + +struct s5k6aa { + struct v4l2_subdev sd; + struct media_pad pad; + + enum v4l2_mbus_type bus_type; + u8 mipi_lanes; + + int (*s_power)(int enable); + struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES]; + struct s5k6aa_gpio gpio[GPIO_NUM]; + + /* external master clock frequency */ + unsigned long mclk_frequency; + /* ISP internal master clock frequency */ + u16 clk_fop; + /* output pixel clock frequency range */ + u16 pclk_fmin; + u16 pclk_fmax; + + unsigned int inv_hflip:1; + unsigned int inv_vflip:1; + + /* protects the struct members below */ + struct mutex lock; + + /* sensor matrix scan window */ + struct v4l2_rect ccd_rect; + + struct s5k6aa_ctrls ctrls; + struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS]; + struct s5k6aa_preset *preset; + const struct s5k6aa_interval *fiv; + + unsigned int streaming:1; + unsigned int apply_cfg:1; + unsigned int apply_crop:1; + unsigned int power; +}; + +static struct s5k6aa_regval s5k6aa_analog_config[] = { + /* Analog settings */ + { 0x112a, 0x0000 }, { 0x1132, 0x0000 }, + { 0x113e, 0x0000 }, { 0x115c, 0x0000 }, + { 0x1164, 0x0000 }, { 0x1174, 0x0000 }, + { 0x1178, 0x0000 }, { 0x077a, 0x0000 }, + { 0x077c, 0x0000 }, { 0x077e, 0x0000 }, + { 0x0780, 0x0000 }, { 0x0782, 0x0000 }, + { 0x0784, 0x0000 }, { 0x0786, 0x0000 }, + { 0x0788, 0x0000 }, { 0x07a2, 0x0000 }, + { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 }, + { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 }, + { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 }, + { 0x07bc, 0x0004 }, { 0x07be, 0x0005 }, + { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 }, +}; + +/* TODO: Add RGB888 and Bayer format */ +static const struct s5k6aa_pixfmt s5k6aa_formats[] = { + { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 }, + /* range 16-240 */ + { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 }, + { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 }, +}; + +static const struct s5k6aa_interval s5k6aa_intervals[] = { + { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */ + { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */ + { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */ + { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */ + { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */ +}; + +#define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */ + +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd; +} + +static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd) +{ + return container_of(sd, struct s5k6aa, sd); +} + +/* Set initial values for all preview presets */ +static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa) +{ + struct s5k6aa_preset *preset = &s5k6aa->presets[0]; + int i; + + for (i = 0; i < S5K6AA_MAX_PRESETS; i++) { + preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF; + preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF; + preset->mbus_fmt.code = s5k6aa_formats[0].code; + preset->index = i; + preset->clk_id = 0; + preset++; + } + + s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX]; + s5k6aa->preset = &s5k6aa->presets[0]; +} + +static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val) +{ + u8 wbuf[2] = {addr >> 8, addr & 0xFF}; + struct i2c_msg msg[2]; + u8 rbuf[2]; + int ret; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = wbuf; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = rbuf; + + ret = i2c_transfer(client->adapter, msg, 2); + *val = be16_to_cpu(*((u16 *)rbuf)); + + v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); + + return ret == 2 ? 0 : ret; +} + +static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val) +{ + u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF}; + + int ret = i2c_master_send(client, buf, 4); + v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val); + + return ret == 4 ? 0 : ret; +} + +/* The command register write, assumes Command_Wr_addH = 0x7000. */ +static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val) +{ + int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr); + if (ret) + return ret; + return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val); +} + +/* The command register read, assumes Command_Rd_addH = 0x7000. */ +static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val) +{ + int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr); + if (ret) + return ret; + return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val); +} + +static int s5k6aa_write_array(struct v4l2_subdev *sd, + const struct s5k6aa_regval *msg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 addr_incr = 0; + int ret = 0; + + while (msg->addr != S5K6AA_TERM) { + if (addr_incr != 2) + ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL, + msg->addr); + if (ret) + break; + ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val); + if (ret) + break; + /* Assume that msg->addr is always less than 0xfffc */ + addr_incr = (msg + 1)->addr - msg->addr; + msg++; + } + + return ret; +} + +/* Configure the AHB high address bytes for GTG registers access */ +static int s5k6aa_set_ahb_address(struct i2c_client *client) +{ + int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH); + if (ret) + return ret; + ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH); + if (ret) + return ret; + return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH); +} + +/** + * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration + * + * Configure the internal ISP PLL for the required output frequency. + * Locking: called with s5k6aa.lock mutex held. + */ +static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa) +{ + struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); + unsigned long fmclk = s5k6aa->mclk_frequency / 1000; + u16 status; + int ret; + + if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ, + "Invalid clock frequency: %ld\n", fmclk)) + return -EINVAL; + + s5k6aa->pclk_fmin = PCLK_FREQ_MIN; + s5k6aa->pclk_fmax = PCLK_FREQ_MAX; + s5k6aa->clk_fop = SYS_PLL_OUT_FREQ; + + /* External input clock frequency in kHz */ + ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16); + if (!ret) + ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF); + if (!ret) + ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1); + /* Internal PLL frequency */ + if (!ret) + ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop); + if (!ret) + ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0), + s5k6aa->pclk_fmin); + if (!ret) + ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0), + s5k6aa->pclk_fmax); + if (!ret) + ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1); + if (!ret) + ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status); + + return ret ? ret : (status ? -EINVAL : 0); +} + +/* Set horizontal and vertical image flipping */ +static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + int index = s5k6aa->preset->index; + + unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip; + unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1); + + return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip); +} + +/* Configure auto/manual white balance and R/G/B gains */ +static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb) +{ + struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); + struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; + u16 reg; + + int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, ®); + + if (!ret && !awb) { + ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val); + if (!ret) + ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1); + if (ret) + return ret; + + ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val); + if (!ret) + ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1); + if (ret) + return ret; + + ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val); + if (!ret) + ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1); + } + if (!ret) { + reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK; + ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg); + } + + return ret; +} + +/* Program FW with exposure time, 'exposure' in us units */ +static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure) +{ + unsigned int time = exposure / 10; + + int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff); + if (!ret) + ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16); + if (ret) + return ret; + return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1); +} + +static int s5k6aa_set_user_gain(struct i2c_client *client, int gain) +{ + int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain); + if (ret) + return ret; + return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1); +} + +/* Set auto/manual exposure and total gain */ +static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value) +{ + struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); + unsigned int exp_time = s5k6aa->ctrls.exposure->val; + u16 auto_alg; + + int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg); + if (ret) + return ret; + + v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n", + exp_time, value, auto_alg); + + if (value == V4L2_EXPOSURE_AUTO) { + auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK; + } else { + ret = s5k6aa_set_user_exposure(c, exp_time); + if (ret) + return ret; + ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val); + if (ret) + return ret; + auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK); + } + + return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg); +} + +static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + u16 auto_alg; + int ret; + + ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg); + if (ret) + return ret; + + if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) { + auto_alg |= AALG_FLICKER_EN_MASK; + } else { + auto_alg &= ~AALG_FLICKER_EN_MASK; + /* The V4L2_CID_LINE_FREQUENCY control values match + * the register values */ + ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value); + if (ret) + return ret; + ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1); + if (ret) + return ret; + } + + return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg); +} + +static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + static const struct v4l2_control colorfx[] = { + { V4L2_COLORFX_NONE, 0 }, + { V4L2_COLORFX_BW, 1 }, + { V4L2_COLORFX_NEGATIVE, 2 }, + { V4L2_COLORFX_SEPIA, 3 }, + { V4L2_COLORFX_SKY_BLUE, 4 }, + { V4L2_COLORFX_SKETCH, 5 }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(colorfx); i++) { + if (colorfx[i].id == val) + return s5k6aa_write(client, REG_G_SPEC_EFFECTS, + colorfx[i].value); + } + return -EINVAL; +} + +static int s5k6aa_preview_config_status(struct i2c_client *client) +{ + u16 error = 0; + int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error); + + v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret); + return ret ? ret : (error ? -EINVAL : 0); +} + +static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa, + struct v4l2_mbus_framefmt *mf) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++) + if (mf->colorspace == s5k6aa_formats[i].colorspace && + mf->code == s5k6aa_formats[i].code) + return i; + return 0; +} + +static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa, + struct s5k6aa_preset *preset) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt); + int ret; + + ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index), + preset->mbus_fmt.width); + if (!ret) + ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index), + preset->mbus_fmt.height); + if (!ret) + ret = s5k6aa_write(client, REG_P_FMT(preset->index), + s5k6aa_formats[fmt_index].reg_p_fmt); + return ret; +} + +static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa) +{ + struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); + struct v4l2_rect *r = &s5k6aa->ccd_rect; + int ret; + + ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width); + if (!ret) + ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height); + if (!ret) + ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left); + if (!ret) + ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top); + if (!ret) + ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1); + if (!ret) + s5k6aa->apply_crop = 0; + + return ret; +} + +/** + * s5k6aa_configure_video_bus - configure the video output interface + * @bus_type: video bus type: parallel or MIPI-CSI + * @nlanes: number of MIPI lanes to be used (MIPI-CSI only) + * + * Note: Only parallel bus operation has been tested. + */ +static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa, + enum v4l2_mbus_type bus_type, int nlanes) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + u16 cfg = 0; + int ret; + + /* + * TODO: The sensor is supposed to support BT.601 and BT.656 + * but there is nothing indicating how to switch between both + * in the datasheet. For now default BT.601 interface is assumed. + */ + if (bus_type == V4L2_MBUS_CSI2) + cfg = nlanes; + else if (bus_type != V4L2_MBUS_PARALLEL) + return -EINVAL; + + ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg); + if (ret) + return ret; + return s5k6aa_write(client, REG_OIF_CFG_CHG, 1); +} + +/* This function should be called when switching to new user configuration set*/ +static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout, + int cid) +{ + unsigned long end = jiffies + msecs_to_jiffies(timeout); + u16 reg = 1; + int ret; + + ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid); + if (!ret) + ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); + if (!ret) + ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1); + if (timeout == 0) + return ret; + + while (ret >= 0 && time_is_after_jiffies(end)) { + ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, ®); + if (!reg) + return 0; + usleep_range(1000, 5000); + } + return ret ? ret : -ETIMEDOUT; +} + +/** + * s5k6aa_set_prev_config - write user preview register set + * + * Configure output resolution and color fromat, pixel clock + * frequency range, device frame rate type and frame period range. + */ +static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa, + struct s5k6aa_preset *preset) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + int idx = preset->index; + u16 frame_rate_q; + int ret; + + if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME) + frame_rate_q = FR_RATE_Q_BEST_FRRATE; + else + frame_rate_q = FR_RATE_Q_BEST_QUALITY; + + ret = s5k6aa_set_output_framefmt(s5k6aa, preset); + if (!ret) + ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx), + s5k6aa->pclk_fmax); + if (!ret) + ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx), + s5k6aa->pclk_fmin); + if (!ret) + ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx), + preset->clk_id); + if (!ret) + ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx), + FR_RATE_DYNAMIC); + if (!ret) + ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx), + frame_rate_q); + if (!ret) + ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx), + s5k6aa->fiv->reg_fr_time + 33); + if (!ret) + ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx), + s5k6aa->fiv->reg_fr_time - 33); + if (!ret) + ret = s5k6aa_new_config_sync(client, 250, idx); + if (!ret) + ret = s5k6aa_preview_config_status(client); + if (!ret) + s5k6aa->apply_cfg = 0; + + v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n", + s5k6aa->fiv->reg_fr_time, ret); + return ret; +} + +/** + * s5k6aa_initialize_isp - basic ISP MCU initialization + * + * Configure AHB addresses for registers read/write; configure PLLs for + * required output pixel clock. The ISP power supply needs to be already + * enabled, with an optional H/W reset. + * Locking: called with s5k6aa.lock mutex held. + */ +static int s5k6aa_initialize_isp(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret; + + s5k6aa->apply_crop = 1; + s5k6aa->apply_cfg = 1; + msleep(100); + + ret = s5k6aa_set_ahb_address(client); + if (ret) + return ret; + ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type, + s5k6aa->mipi_lanes); + if (ret) + return ret; + ret = s5k6aa_write_array(sd, s5k6aa_analog_config); + if (ret) + return ret; + msleep(20); + + return s5k6aa_configure_pixel_clocks(s5k6aa); +} + +static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val) +{ + if (!gpio_is_valid(priv->gpio[id].gpio)) + return 0; + gpio_set_value(priv->gpio[id].gpio, !!val); + return 1; +} + +static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id) +{ + return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level); +} + +static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id) +{ + return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level); +} + +static int __s5k6aa_power_on(struct s5k6aa *s5k6aa) +{ + int ret; + + ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); + if (ret) + return ret; + if (s5k6aa_gpio_deassert(s5k6aa, STBY)) + usleep_range(150, 200); + + if (s5k6aa->s_power) + ret = s5k6aa->s_power(1); + usleep_range(4000, 4000); + + if (s5k6aa_gpio_deassert(s5k6aa, RST)) + msleep(20); + + return ret; +} + +static int __s5k6aa_power_off(struct s5k6aa *s5k6aa) +{ + int ret; + + if (s5k6aa_gpio_assert(s5k6aa, RST)) + usleep_range(100, 150); + + if (s5k6aa->s_power) { + ret = s5k6aa->s_power(0); + if (ret) + return ret; + } + if (s5k6aa_gpio_assert(s5k6aa, STBY)) + usleep_range(50, 100); + s5k6aa->streaming = 0; + + return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); +} + +/* + * V4L2 subdev core and video operations + */ +static int s5k6aa_set_power(struct v4l2_subdev *sd, int on) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret = 0; + + mutex_lock(&s5k6aa->lock); + + if (!on == s5k6aa->power) { + if (on) { + ret = __s5k6aa_power_on(s5k6aa); + if (!ret) + ret = s5k6aa_initialize_isp(sd); + } else { + ret = __s5k6aa_power_off(s5k6aa); + } + + if (!ret) + s5k6aa->power += on ? 1 : -1; + } + + mutex_unlock(&s5k6aa->lock); + + if (!on || ret || s5k6aa->power != 1) + return ret; + + return v4l2_ctrl_handler_setup(sd->ctrl_handler); +} + +static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + int ret = 0; + + ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable); + if (!ret) + ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1); + if (!ret) + s5k6aa->streaming = enable; + + return ret; +} + +static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret = 0; + + mutex_lock(&s5k6aa->lock); + + if (s5k6aa->streaming == !on) { + if (!ret && s5k6aa->apply_cfg) + ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset); + if (s5k6aa->apply_crop) + ret = s5k6aa_set_input_params(s5k6aa); + if (!ret) + ret = __s5k6aa_stream(s5k6aa, !!on); + } + mutex_unlock(&s5k6aa->lock); + + return ret; +} + +static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + + mutex_lock(&s5k6aa->lock); + fi->interval = s5k6aa->fiv->interval; + mutex_unlock(&s5k6aa->lock); + + return 0; +} + +static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa, + struct v4l2_subdev_frame_interval *fi) +{ + struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt; + const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0]; + unsigned int err, min_err = UINT_MAX; + unsigned int i, fr_time; + + if (fi->interval.denominator == 0) + return -EINVAL; + + fr_time = fi->interval.numerator * 10000 / fi->interval.denominator; + + for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) { + const struct s5k6aa_interval *iv = &s5k6aa_intervals[i]; + + if (mbus_fmt->width > iv->size.width || + mbus_fmt->height > iv->size.height) + continue; + + err = abs(iv->reg_fr_time - fr_time); + if (err < min_err) { + fiv = iv; + min_err = err; + } + } + s5k6aa->fiv = fiv; + + v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n", + fiv->reg_fr_time * 100); + return 0; +} + +static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret; + + v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n", + fi->interval.numerator, fi->interval.denominator); + + mutex_lock(&s5k6aa->lock); + ret = __s5k6aa_set_frame_interval(s5k6aa, fi); + s5k6aa->apply_cfg = 1; + + mutex_unlock(&s5k6aa->lock); + return ret; +} + +/* + * V4L2 subdev pad level and video operations + */ +static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_interval_enum *fie) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + const struct s5k6aa_interval *fi; + int ret = 0; + + if (fie->index > ARRAY_SIZE(s5k6aa_intervals)) + return -EINVAL; + + v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN, + S5K6AA_WIN_WIDTH_MAX, 1, + &fie->height, S5K6AA_WIN_HEIGHT_MIN, + S5K6AA_WIN_HEIGHT_MAX, 1, 0); + + mutex_lock(&s5k6aa->lock); + fi = &s5k6aa_intervals[fie->index]; + if (fie->width > fi->size.width || fie->height > fi->size.height) + ret = -EINVAL; + else + fie->interval = fi->interval; + mutex_unlock(&s5k6aa->lock); + + return ret; +} + +static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(s5k6aa_formats)) + return -EINVAL; + + code->code = s5k6aa_formats[code->index].code; + return 0; +} + +static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + int i = ARRAY_SIZE(s5k6aa_formats); + + if (fse->index > 0) + return -EINVAL; + + while (--i) + if (fse->code == s5k6aa_formats[i].code) + break; + + fse->code = s5k6aa_formats[i].code; + fse->min_width = S5K6AA_WIN_WIDTH_MIN; + fse->max_width = S5K6AA_WIN_WIDTH_MAX; + fse->max_height = S5K6AA_WIN_HEIGHT_MIN; + fse->min_height = S5K6AA_WIN_HEIGHT_MAX; + + return 0; +} + +static struct v4l2_rect * +__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + return &s5k6aa->ccd_rect; + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(fh, 0); + + return NULL; +} + +static void s5k6aa_try_format(struct s5k6aa *s5k6aa, + struct v4l2_mbus_framefmt *mf) +{ + unsigned int index; + + v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN, + S5K6AA_WIN_WIDTH_MAX, 1, + &mf->height, S5K6AA_WIN_HEIGHT_MIN, + S5K6AA_WIN_HEIGHT_MAX, 1, 0); + + if (mf->colorspace != V4L2_COLORSPACE_JPEG && + mf->colorspace != V4L2_COLORSPACE_REC709) + mf->colorspace = V4L2_COLORSPACE_JPEG; + + index = s5k6aa_get_pixfmt_index(s5k6aa, mf); + + mf->colorspace = s5k6aa_formats[index].colorspace; + mf->code = s5k6aa_formats[index].code; + mf->field = V4L2_FIELD_NONE; +} + +static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + struct v4l2_mbus_framefmt *mf; + + memset(fmt->reserved, 0, sizeof(fmt->reserved)); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, 0); + fmt->format = *mf; + return 0; + } + + mutex_lock(&s5k6aa->lock); + fmt->format = s5k6aa->preset->mbus_fmt; + mutex_unlock(&s5k6aa->lock); + + return 0; +} + +static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + struct s5k6aa_preset *preset = s5k6aa->preset; + struct v4l2_mbus_framefmt *mf; + struct v4l2_rect *crop; + int ret = 0; + + mutex_lock(&s5k6aa->lock); + s5k6aa_try_format(s5k6aa, &fmt->format); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + crop = v4l2_subdev_get_try_crop(fh, 0); + } else { + if (s5k6aa->streaming) { + ret = -EBUSY; + } else { + mf = &preset->mbus_fmt; + crop = &s5k6aa->ccd_rect; + s5k6aa->apply_cfg = 1; + } + } + + if (ret == 0) { + struct v4l2_subdev_frame_interval fiv = { + .interval = {0, 1} + }; + + *mf = fmt->format; + /* + * Make sure the crop window is valid, i.e. its size is + * greater than the output window, as the ISP supports + * only down-scaling. + */ + crop->width = clamp_t(unsigned int, crop->width, mf->width, + S5K6AA_WIN_WIDTH_MAX); + crop->height = clamp_t(unsigned int, crop->height, mf->height, + S5K6AA_WIN_HEIGHT_MAX); + crop->left = clamp_t(unsigned int, crop->left, 0, + S5K6AA_WIN_WIDTH_MAX - crop->width); + crop->top = clamp_t(unsigned int, crop->top, 0, + S5K6AA_WIN_HEIGHT_MAX - crop->height); + + /* Reset to minimum possible frame interval */ + ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv); + } + mutex_unlock(&s5k6aa->lock); + + return ret; +} + +static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + struct v4l2_rect *rect; + + memset(crop->reserved, 0, sizeof(crop->reserved)); + mutex_lock(&s5k6aa->lock); + + rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); + if (rect) + crop->rect = *rect; + + mutex_unlock(&s5k6aa->lock); + + v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n", + rect->left, rect->top, rect->width, rect->height); + + return 0; +} + +static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + struct v4l2_mbus_framefmt *mf; + unsigned int max_x, max_y; + struct v4l2_rect *crop_r; + + mutex_lock(&s5k6aa->lock); + crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); + + if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + mf = &s5k6aa->preset->mbus_fmt; + s5k6aa->apply_crop = 1; + } else { + mf = v4l2_subdev_get_try_format(fh, 0); + } + v4l_bound_align_image(&crop->rect.width, mf->width, + S5K6AA_WIN_WIDTH_MAX, 1, + &crop->rect.height, mf->height, + S5K6AA_WIN_HEIGHT_MAX, 1, 0); + + max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1; + max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1; + + crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x); + crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y); + + *crop_r = crop->rect; + + mutex_unlock(&s5k6aa->lock); + + v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n", + crop_r->left, crop_r->top, crop_r->width, crop_r->height); + + return 0; +} + +static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = { + .enum_mbus_code = s5k6aa_enum_mbus_code, + .enum_frame_size = s5k6aa_enum_frame_size, + .enum_frame_interval = s5k6aa_enum_frame_interval, + .get_fmt = s5k6aa_get_fmt, + .set_fmt = s5k6aa_set_fmt, + .get_crop = s5k6aa_get_crop, + .set_crop = s5k6aa_set_crop, +}; + +static const struct v4l2_subdev_video_ops s5k6aa_video_ops = { + .g_frame_interval = s5k6aa_g_frame_interval, + .s_frame_interval = s5k6aa_s_frame_interval, + .s_stream = s5k6aa_s_stream, +}; + +/* + * V4L2 subdev controls + */ + +static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int idx, err = 0; + + v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val); + + mutex_lock(&s5k6aa->lock); + /* + * If the device is not powered up by the host driver do + * not apply any controls to H/W at this time. Instead + * the controls will be restored right after power-up. + */ + if (s5k6aa->power == 0) + goto unlock; + idx = s5k6aa->preset->index; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + err = s5k6aa_set_awb(s5k6aa, ctrl->val); + break; + + case V4L2_CID_BRIGHTNESS: + err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val); + break; + + case V4L2_CID_COLORFX: + err = s5k6aa_set_colorfx(s5k6aa, ctrl->val); + break; + + case V4L2_CID_CONTRAST: + err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val); + break; + + case V4L2_CID_EXPOSURE_AUTO: + err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val); + break; + + case V4L2_CID_HFLIP: + err = s5k6aa_set_mirror(s5k6aa, ctrl->val); + if (err) + break; + err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); + break; + + case V4L2_CID_POWER_LINE_FREQUENCY: + err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val); + break; + + case V4L2_CID_SATURATION: + err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val); + break; + + case V4L2_CID_SHARPNESS: + err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val); + break; + + case V4L2_CID_WHITE_BALANCE_TEMPERATURE: + err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val); + if (err) + break; + err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); + break; + } +unlock: + mutex_unlock(&s5k6aa->lock); + return err; +} + +static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = { + .s_ctrl = s5k6aa_s_ctrl, +}; + +static int s5k6aa_log_status(struct v4l2_subdev *sd) +{ + v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); + return 0; +} + +#define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001) +#define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002) +#define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003) + +static const struct v4l2_ctrl_config s5k6aa_ctrls[] = { + { + .ops = &s5k6aa_ctrl_ops, + .id = V4L2_CID_RED_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Red", + .min = 0, + .max = 256, + .def = 127, + .step = 1, + }, { + .ops = &s5k6aa_ctrl_ops, + .id = V4L2_CID_GREEN_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Green", + .min = 0, + .max = 256, + .def = 127, + .step = 1, + }, { + .ops = &s5k6aa_ctrl_ops, + .id = V4L2_CID_BLUE_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Blue", + .min = 0, + .max = 256, + .def = 127, + .step = 1, + }, +}; + +static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa) +{ + const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops; + struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + + int ret = v4l2_ctrl_handler_init(hdl, 16); + if (ret) + return ret; + /* Auto white balance cluster */ + ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); + ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL); + ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL); + ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL); + v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false); + + ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_cluster(2, &ctrls->hflip); + + ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, + V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); + /* Exposure time: x 1 us */ + ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, + 0, 6000000U, 1, 100000U); + /* Total gain: 256 <=> 1x */ + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, + 0, 256, 1, 256); + v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false); + + v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO); + + v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, + V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE); + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE, + 0, 256, 1, 0); + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0); + + if (hdl->error) { + ret = hdl->error; + v4l2_ctrl_handler_free(hdl); + return ret; + } + + s5k6aa->sd.ctrl_handler = hdl; + return 0; +} + +/* + * V4L2 subdev internal operations + */ +static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0); + + format->colorspace = s5k6aa_formats[0].colorspace; + format->code = s5k6aa_formats[0].code; + format->width = S5K6AA_OUT_WIDTH_DEF; + format->height = S5K6AA_OUT_HEIGHT_DEF; + format->field = V4L2_FIELD_NONE; + + crop->width = S5K6AA_WIN_WIDTH_MAX; + crop->height = S5K6AA_WIN_HEIGHT_MAX; + crop->left = 0; + crop->top = 0; + + return 0; +} + +int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa) +{ + struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); + u16 api_ver = 0, fw_rev = 0; + + int ret = s5k6aa_set_ahb_address(client); + + if (!ret) + ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver); + if (!ret) + ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev); + if (ret) { + v4l2_err(&s5k6aa->sd, "FW revision check failed!\n"); + return ret; + } + + v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n", + api_ver, fw_rev); + + return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV; +} + +static int s5k6aa_registered(struct v4l2_subdev *sd) +{ + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + int ret; + + mutex_lock(&s5k6aa->lock); + ret = __s5k6aa_power_on(s5k6aa); + if (!ret) { + msleep(100); + ret = s5k6aa_check_fw_revision(s5k6aa); + __s5k6aa_power_off(s5k6aa); + } + mutex_unlock(&s5k6aa->lock); + + return ret; +} + +static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = { + .registered = s5k6aa_registered, + .open = s5k6aa_open, +}; + +static const struct v4l2_subdev_core_ops s5k6aa_core_ops = { + .s_power = s5k6aa_set_power, + .log_status = s5k6aa_log_status, +}; + +static const struct v4l2_subdev_ops s5k6aa_subdev_ops = { + .core = &s5k6aa_core_ops, + .pad = &s5k6aa_pad_ops, + .video = &s5k6aa_video_ops, +}; + +/* + * GPIO setup + */ +static int s5k6aa_configure_gpio(int nr, int val, const char *name) +{ + unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + int ret; + + if (!gpio_is_valid(nr)) + return 0; + ret = gpio_request_one(nr, flags, name); + if (!ret) + gpio_export(nr, 0); + return ret; +} + +static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) { + if (!gpio_is_valid(s5k6aa->gpio[i].gpio)) + continue; + gpio_free(s5k6aa->gpio[i].gpio); + s5k6aa->gpio[i].gpio = -EINVAL; + } +} + +static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa, + const struct s5k6aa_platform_data *pdata) +{ + const struct s5k6aa_gpio *gpio = &pdata->gpio_stby; + int ret; + + s5k6aa->gpio[STBY].gpio = -EINVAL; + s5k6aa->gpio[RST].gpio = -EINVAL; + + ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY"); + if (ret) { + s5k6aa_free_gpios(s5k6aa); + return ret; + } + s5k6aa->gpio[STBY] = *gpio; + if (gpio_is_valid(gpio->gpio)) + gpio_set_value(gpio->gpio, 0); + + gpio = &pdata->gpio_reset; + ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST"); + if (ret) { + s5k6aa_free_gpios(s5k6aa); + return ret; + } + s5k6aa->gpio[RST] = *gpio; + if (gpio_is_valid(gpio->gpio)) + gpio_set_value(gpio->gpio, 0); + + return 0; +} + +static int s5k6aa_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct s5k6aa_platform_data *pdata = client->dev.platform_data; + struct v4l2_subdev *sd; + struct s5k6aa *s5k6aa; + int i, ret; + + if (pdata == NULL) { + dev_err(&client->dev, "Platform data not specified\n"); + return -EINVAL; + } + + if (pdata->mclk_frequency == 0) { + dev_err(&client->dev, "MCLK frequency not specified\n"); + return -EINVAL; + } + + s5k6aa = kzalloc(sizeof(*s5k6aa), GFP_KERNEL); + if (!s5k6aa) + return -ENOMEM; + + mutex_init(&s5k6aa->lock); + + s5k6aa->mclk_frequency = pdata->mclk_frequency; + s5k6aa->bus_type = pdata->bus_type; + s5k6aa->mipi_lanes = pdata->nlanes; + s5k6aa->s_power = pdata->set_power; + s5k6aa->inv_hflip = pdata->horiz_flip; + s5k6aa->inv_vflip = pdata->vert_flip; + + sd = &s5k6aa->sd; + strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); + v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); + + sd->internal_ops = &s5k6aa_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0); + if (ret) + goto out_err1; + + ret = s5k6aa_configure_gpios(s5k6aa, pdata); + if (ret) + goto out_err2; + + for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++) + s5k6aa->supplies[i].supply = s5k6aa_supply_names[i]; + + ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES, + s5k6aa->supplies); + if (ret) { + dev_err(&client->dev, "Failed to get regulators\n"); + goto out_err3; + } + + ret = s5k6aa_initialize_ctrls(s5k6aa); + if (ret) + goto out_err4; + + s5k6aa_presets_data_init(s5k6aa); + + s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX; + s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX; + s5k6aa->ccd_rect.left = 0; + s5k6aa->ccd_rect.top = 0; + + return 0; + +out_err4: + regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); +out_err3: + s5k6aa_free_gpios(s5k6aa); +out_err2: + media_entity_cleanup(&s5k6aa->sd.entity); +out_err1: + kfree(s5k6aa); + return ret; +} + +static int s5k6aa_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct s5k6aa *s5k6aa = to_s5k6aa(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(sd->ctrl_handler); + media_entity_cleanup(&sd->entity); + regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); + s5k6aa_free_gpios(s5k6aa); + kfree(s5k6aa); + + return 0; +} + +static const struct i2c_device_id s5k6aa_id[] = { + { DRIVER_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, s5k6aa_id); + + +static struct i2c_driver s5k6aa_i2c_driver = { + .driver = { + .name = DRIVER_NAME + }, + .probe = s5k6aa_probe, + .remove = s5k6aa_remove, + .id_table = s5k6aa_id, +}; + +static int __init s5k6aa_init(void) +{ + return i2c_add_driver(&s5k6aa_i2c_driver); +} + +static void __exit s5k6aa_exit(void) +{ + i2c_del_driver(&s5k6aa_i2c_driver); +} + +module_init(s5k6aa_init); +module_exit(s5k6aa_exit); + +MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_LICENSE("GPL"); diff --git a/include/media/s5k6aa.h b/include/media/s5k6aa.h new file mode 100644 index 000000000000..ba34f7055e55 --- /dev/null +++ b/include/media/s5k6aa.h @@ -0,0 +1,51 @@ +/* + * S5K6AAFX camera sensor driver header + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5K6AA_H +#define S5K6AA_H + +#include + +/** + * struct s5k6aa_gpio - data structure describing a GPIO + * @gpio: GPIO number + * @level: indicates active state of the @gpio + */ +struct s5k6aa_gpio { + int gpio; + int level; +}; + +/** + * struct s5k6aa_platform_data - s5k6aa driver platform data + * @set_power: an additional callback to the board code, called + * after enabling the regulators and before switching + * the sensor off + * @mclk_frequency: sensor's master clock frequency in Hz + * @gpio_reset: GPIO driving RESET pin + * @gpio_stby: GPIO driving STBY pin + * @nlanes: maximum number of MIPI-CSI lanes used + * @horiz_flip: default horizontal image flip value, non zero to enable + * @vert_flip: default vertical image flip value, non zero to enable + */ + +struct s5k6aa_platform_data { + int (*set_power)(int enable); + unsigned long mclk_frequency; + struct s5k6aa_gpio gpio_reset; + struct s5k6aa_gpio gpio_stby; + enum v4l2_mbus_type bus_type; + u8 nlanes; + u8 horiz_flip; + u8 vert_flip; +}; + +#endif /* S5K6AA_H */ From 6f524ec156ba31a18425fad9dd1287be0701d9d1 Mon Sep 17 00:00:00 2001 From: Scott Jiang <[scott.jiang.linux@gmail.com]> Date: Wed, 21 Sep 2011 09:25:23 -0300 Subject: [PATCH 1363/1596] [media] vb2: add vb2_get_unmapped_area in vb2 core no mmu system needs get_unmapped_area file operations to do mmap Signed-off-by: Scott Jiang Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 31 ++++++++++++++++++++++++++++ include/media/videobuf2-core.h | 7 +++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 9005dc9991ab..979e544388cb 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -1567,6 +1567,37 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) } EXPORT_SYMBOL_GPL(vb2_mmap); +#ifndef CONFIG_MMU +unsigned long vb2_get_unmapped_area(struct vb2_queue *q, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags) +{ + unsigned long off = pgoff << PAGE_SHIFT; + struct vb2_buffer *vb; + unsigned int buffer, plane; + int ret; + + if (q->memory != V4L2_MEMORY_MMAP) { + dprintk(1, "Queue is not currently set up for mmap\n"); + return -EINVAL; + } + + /* + * Find the plane corresponding to the offset passed by userspace. + */ + ret = __find_plane_by_offset(q, off, &buffer, &plane); + if (ret) + return ret; + + vb = q->bufs[buffer]; + + return (unsigned long)vb2_plane_vaddr(vb, plane); +} +EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); +#endif + static int __vb2_init_fileio(struct vb2_queue *q, int read); static int __vb2_cleanup_fileio(struct vb2_queue *q); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 55c57d3d3e63..a15d1f1b319e 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -322,6 +322,13 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type); int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type); int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma); +#ifndef CONFIG_MMU +unsigned long vb2_get_unmapped_area(struct vb2_queue *q, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags); +#endif unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait); size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, loff_t *ppos, int nonblock); From 57f6217be1d129e3e38bac3eadc20cbf909666b6 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 30 Sep 2011 07:56:02 -0300 Subject: [PATCH 1364/1596] [media] MFC: Change MFC firmware binary name This patch renames the MFC firmware binary to avoid SoC name in it. Signed-off-by: Sachin Kamat Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c index 5f4da80051bb..f2481a85e0a2 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c @@ -38,7 +38,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) * into kernel. */ mfc_debug_enter(); err = request_firmware((const struct firmware **)&fw_blob, - "s5pc110-mfc.fw", dev->v4l2_dev.dev); + "s5p-mfc.fw", dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; @@ -116,7 +116,7 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) * into kernel. */ mfc_debug_enter(); err = request_firmware((const struct firmware **)&fw_blob, - "s5pc110-mfc.fw", dev->v4l2_dev.dev); + "s5p-mfc.fw", dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; From 63b4ca23ed2b35742bebf8cb2af49b84b24442c6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 22 Sep 2011 16:54:34 -0300 Subject: [PATCH 1365/1596] [media] omap3isp: Move media_entity_cleanup() from unregister() to cleanup() The media_entity_cleanup() function belong to the module cleanup handlers, not the entity registration handlers. Move it there. Create a omap3isp_video_cleanup() function to cleanup the video node entity, and call it from the module cleanup handlers. Rename omap3isp_stat_free() to omap3isp_stat_cleanup(). Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 5 +++-- drivers/media/video/omap3isp/ispccp2.c | 5 +++-- drivers/media/video/omap3isp/ispcsi2.c | 6 ++++-- drivers/media/video/omap3isp/isph3a_aewb.c | 2 +- drivers/media/video/omap3isp/isph3a_af.c | 2 +- drivers/media/video/omap3isp/isphist.c | 2 +- drivers/media/video/omap3isp/isppreview.c | 9 ++++++--- drivers/media/video/omap3isp/ispresizer.c | 7 +++++-- drivers/media/video/omap3isp/ispstat.c | 4 ++-- drivers/media/video/omap3isp/ispstat.h | 2 +- drivers/media/video/omap3isp/ispvideo.c | 9 ++++++--- drivers/media/video/omap3isp/ispvideo.h | 1 + 12 files changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 253fdcce2df2..98804d5f89c2 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2206,8 +2206,6 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) { - media_entity_cleanup(&ccdc->subdev.entity); - v4l2_device_unregister_subdev(&ccdc->subdev); omap3isp_video_unregister(&ccdc->video_out); } @@ -2287,6 +2285,9 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) { struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + omap3isp_video_cleanup(&ccdc->video_out); + media_entity_cleanup(&ccdc->subdev.entity); + /* Free LSC requests. As the CCDC is stopped there's no active request, * so only the pending request and the free queue need to be handled. */ diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index fa1d09b0ad98..b8e0863b194c 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -1100,8 +1100,6 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) */ void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) { - media_entity_cleanup(&ccp2->subdev.entity); - v4l2_device_unregister_subdev(&ccp2->subdev); omap3isp_video_unregister(&ccp2->video_in); } @@ -1146,6 +1144,9 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp) { struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; + omap3isp_video_cleanup(&ccp2->video_in); + media_entity_cleanup(&ccp2->subdev.entity); + regulator_put(ccp2->vdds_csib); } diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 69161a682b3d..5612e95ac0b8 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -1241,8 +1241,6 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) { - media_entity_cleanup(&csi2->subdev.entity); - v4l2_device_unregister_subdev(&csi2->subdev); omap3isp_video_unregister(&csi2->video_out); } @@ -1277,6 +1275,10 @@ int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, */ void omap3isp_csi2_cleanup(struct isp_device *isp) { + struct isp_csi2_device *csi2a = &isp->isp_csi2a; + + omap3isp_video_cleanup(&csi2a->video_out); + media_entity_cleanup(&csi2a->subdev.entity); } /* diff --git a/drivers/media/video/omap3isp/isph3a_aewb.c b/drivers/media/video/omap3isp/isph3a_aewb.c index 8068cefd8d89..a3c76bf18175 100644 --- a/drivers/media/video/omap3isp/isph3a_aewb.c +++ b/drivers/media/video/omap3isp/isph3a_aewb.c @@ -370,5 +370,5 @@ void omap3isp_h3a_aewb_cleanup(struct isp_device *isp) { kfree(isp->isp_aewb.priv); kfree(isp->isp_aewb.recover_priv); - omap3isp_stat_free(&isp->isp_aewb); + omap3isp_stat_cleanup(&isp->isp_aewb); } diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c index ba54d0acdecf..58e0bc414899 100644 --- a/drivers/media/video/omap3isp/isph3a_af.c +++ b/drivers/media/video/omap3isp/isph3a_af.c @@ -425,5 +425,5 @@ void omap3isp_h3a_af_cleanup(struct isp_device *isp) { kfree(isp->isp_af.priv); kfree(isp->isp_af.recover_priv); - omap3isp_stat_free(&isp->isp_af); + omap3isp_stat_cleanup(&isp->isp_af); } diff --git a/drivers/media/video/omap3isp/isphist.c b/drivers/media/video/omap3isp/isphist.c index 1743856b30d1..1163907bcddc 100644 --- a/drivers/media/video/omap3isp/isphist.c +++ b/drivers/media/video/omap3isp/isphist.c @@ -516,5 +516,5 @@ void omap3isp_hist_cleanup(struct isp_device *isp) if (HIST_USING_DMA(&isp->isp_hist)) omap_free_dma(isp->isp_hist.dma_ch); kfree(isp->isp_hist.priv); - omap3isp_stat_free(&isp->isp_hist); + omap3isp_stat_cleanup(&isp->isp_hist); } diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index aba537af87e4..84a18b66b23c 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -2046,10 +2046,7 @@ static int preview_init_entities(struct isp_prev_device *prev) void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) { - media_entity_cleanup(&prev->subdev.entity); - v4l2_device_unregister_subdev(&prev->subdev); - v4l2_ctrl_handler_free(&prev->ctrls); omap3isp_video_unregister(&prev->video_in); omap3isp_video_unregister(&prev->video_out); } @@ -2085,6 +2082,12 @@ int omap3isp_preview_register_entities(struct isp_prev_device *prev, void omap3isp_preview_cleanup(struct isp_device *isp) { + struct isp_prev_device *prev = &isp->isp_prev; + + v4l2_ctrl_handler_free(&prev->ctrls); + omap3isp_video_cleanup(&prev->video_in); + omap3isp_video_cleanup(&prev->video_out); + media_entity_cleanup(&prev->subdev.entity); } /* diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 0bb0f8cd36f5..78ce0406a232 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1674,8 +1674,6 @@ static int resizer_init_entities(struct isp_res_device *res) void omap3isp_resizer_unregister_entities(struct isp_res_device *res) { - media_entity_cleanup(&res->subdev.entity); - v4l2_device_unregister_subdev(&res->subdev); omap3isp_video_unregister(&res->video_in); omap3isp_video_unregister(&res->video_out); @@ -1712,6 +1710,11 @@ int omap3isp_resizer_register_entities(struct isp_res_device *res, void omap3isp_resizer_cleanup(struct isp_device *isp) { + struct isp_res_device *res = &isp->isp_res; + + omap3isp_video_cleanup(&res->video_in); + omap3isp_video_cleanup(&res->video_out); + media_entity_cleanup(&res->subdev.entity); } /* diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index 732905552261..bf0e5a771857 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -1062,7 +1062,6 @@ int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, void omap3isp_stat_unregister_entities(struct ispstat *stat) { - media_entity_cleanup(&stat->subdev.entity); v4l2_device_unregister_subdev(&stat->subdev); } @@ -1085,8 +1084,9 @@ int omap3isp_stat_init(struct ispstat *stat, const char *name, return isp_stat_init_entities(stat, name, sd_ops); } -void omap3isp_stat_free(struct ispstat *stat) +void omap3isp_stat_cleanup(struct ispstat *stat) { + media_entity_cleanup(&stat->subdev.entity); isp_stat_bufs_free(stat); kfree(stat->buf); } diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index d86da94fa50d..9b7c8654dc8a 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h @@ -144,7 +144,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, struct omap3isp_stat_data *data); int omap3isp_stat_init(struct ispstat *stat, const char *name, const struct v4l2_subdev_ops *sd_ops); -void omap3isp_stat_free(struct ispstat *stat); +void omap3isp_stat_cleanup(struct ispstat *stat); int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, struct v4l2_event_subscription *sub); diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 0cb8a9f9d675..7d74ebbdb63b 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -1325,6 +1325,11 @@ int omap3isp_video_init(struct isp_video *video, const char *name) return 0; } +void omap3isp_video_cleanup(struct isp_video *video) +{ + media_entity_cleanup(&video->video.entity); +} + int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) { int ret; @@ -1341,8 +1346,6 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) void omap3isp_video_unregister(struct isp_video *video) { - if (video_is_registered(&video->video)) { - media_entity_cleanup(&video->video.entity); + if (video_is_registered(&video->video)) video_unregister_device(&video->video); - } } diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 53160aa24e6e..08cbfa144e6e 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -190,6 +190,7 @@ struct isp_video_fh { container_of(q, struct isp_video_fh, queue) int omap3isp_video_init(struct isp_video *video, const char *name); +void omap3isp_video_cleanup(struct isp_video *video); int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev); void omap3isp_video_unregister(struct isp_video *video); From 39099d09ae4605003696919d7c3a6e8a96607c4b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 22 Sep 2011 16:59:26 -0300 Subject: [PATCH 1366/1596] [media] omap3isp: Move *_init_entities() functions to the init/cleanup section Group all init/cleanup functions together to make the code more readable. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 62 ++++++------ drivers/media/video/omap3isp/ispccp2.c | 112 +++++++++++----------- drivers/media/video/omap3isp/ispcsi2.c | 84 ++++++++-------- drivers/media/video/omap3isp/isppreview.c | 94 +++++++++--------- drivers/media/video/omap3isp/ispresizer.c | 90 ++++++++--------- drivers/media/video/omap3isp/ispstat.c | 36 +++---- 6 files changed, 239 insertions(+), 239 deletions(-) diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 98804d5f89c2..c30cc59d7032 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2152,6 +2152,37 @@ static const struct media_entity_operations ccdc_media_ops = { .link_setup = ccdc_link_setup, }; +void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) +{ + v4l2_device_unregister_subdev(&ccdc->subdev); + omap3isp_video_unregister(&ccdc->video_out); +} + +int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video node. */ + ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&ccdc->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_ccdc_unregister_entities(ccdc); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP CCDC initialisation and cleanup + */ + /* * ccdc_init_entities - Initialize V4L2 subdev and media entity * @ccdc: ISP CCDC module @@ -2204,37 +2235,6 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) return 0; } -void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) -{ - v4l2_device_unregister_subdev(&ccdc->subdev); - omap3isp_video_unregister(&ccdc->video_out); -} - -int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video node. */ - ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&ccdc->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_ccdc_unregister_entities(ccdc); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP CCDC initialisation and cleanup - */ - /* * omap3isp_ccdc_init - CCDC module initialization. * @dev: Device pointer specific to the OMAP3 ISP. diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index b8e0863b194c..883a2825cb41 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -1031,6 +1031,48 @@ static const struct media_entity_operations ccp2_media_ops = { .link_setup = ccp2_link_setup, }; +/* + * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev + * @ccp2: Pointer to ISP CCP2 device + */ +void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) +{ + v4l2_device_unregister_subdev(&ccp2->subdev); + omap3isp_video_unregister(&ccp2->video_in); +} + +/* + * omap3isp_ccp2_register_entities - Register the subdev media entity + * @ccp2: Pointer to ISP CCP2 device + * @vdev: Pointer to v4l device + * return negative error code or zero on success + */ + +int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&ccp2->video_in, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_ccp2_unregister_entities(ccp2); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP ccp2 initialisation and cleanup + */ + /* * ccp2_init_entities - Initialize ccp2 subdev and media entity. * @ccp2: Pointer to ISP CCP2 device @@ -1094,62 +1136,6 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) return 0; } -/* - * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev - * @ccp2: Pointer to ISP CCP2 device - */ -void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) -{ - v4l2_device_unregister_subdev(&ccp2->subdev); - omap3isp_video_unregister(&ccp2->video_in); -} - -/* - * omap3isp_ccp2_register_entities - Register the subdev media entity - * @ccp2: Pointer to ISP CCP2 device - * @vdev: Pointer to v4l device - * return negative error code or zero on success - */ - -int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&ccp2->video_in, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_ccp2_unregister_entities(ccp2); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP ccp2 initialisation and cleanup - */ - -/* - * omap3isp_ccp2_cleanup - CCP2 un-initialization - * @isp : Pointer to ISP device - */ -void omap3isp_ccp2_cleanup(struct isp_device *isp) -{ - struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; - - omap3isp_video_cleanup(&ccp2->video_in); - media_entity_cleanup(&ccp2->subdev.entity); - - regulator_put(ccp2->vdds_csib); -} - /* * omap3isp_ccp2_init - CCP2 initialization. * @isp : Pointer to ISP device @@ -1195,3 +1181,17 @@ int omap3isp_ccp2_init(struct isp_device *isp) return ret; } + +/* + * omap3isp_ccp2_cleanup - CCP2 un-initialization + * @isp : Pointer to ISP device + */ +void omap3isp_ccp2_cleanup(struct isp_device *isp) +{ + struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; + + omap3isp_video_cleanup(&ccp2->video_in); + media_entity_cleanup(&ccp2->subdev.entity); + + regulator_put(ccp2->vdds_csib); +} diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 5612e95ac0b8..2c9bffcdc5c9 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -1187,6 +1187,37 @@ static const struct media_entity_operations csi2_media_ops = { .link_setup = csi2_link_setup, }; +void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) +{ + v4l2_device_unregister_subdev(&csi2->subdev); + omap3isp_video_unregister(&csi2->video_out); +} + +int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &csi2->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&csi2->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_csi2_unregister_entities(csi2); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP CSI2 initialisation and cleanup + */ + /* * csi2_init_entities - Initialize subdev and media entity. * @csi2: Pointer to csi2 structure. @@ -1239,48 +1270,6 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) return 0; } -void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) -{ - v4l2_device_unregister_subdev(&csi2->subdev); - omap3isp_video_unregister(&csi2->video_out); -} - -int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &csi2->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&csi2->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_csi2_unregister_entities(csi2); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP CSI2 initialisation and cleanup - */ - -/* - * omap3isp_csi2_cleanup - Routine for module driver cleanup - */ -void omap3isp_csi2_cleanup(struct isp_device *isp) -{ - struct isp_csi2_device *csi2a = &isp->isp_csi2a; - - omap3isp_video_cleanup(&csi2a->video_out); - media_entity_cleanup(&csi2a->subdev.entity); -} - /* * omap3isp_csi2_init - Routine for module driver init */ @@ -1317,3 +1306,14 @@ int omap3isp_csi2_init(struct isp_device *isp) omap3isp_csi2_cleanup(isp); return ret; } + +/* + * omap3isp_csi2_cleanup - Routine for module driver cleanup + */ +void omap3isp_csi2_cleanup(struct isp_device *isp) +{ + struct isp_csi2_device *csi2a = &isp->isp_csi2a; + + omap3isp_video_cleanup(&csi2a->video_out); + media_entity_cleanup(&csi2a->subdev.entity); +} diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index 84a18b66b23c..b926ebbaca3a 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -1966,8 +1966,44 @@ static const struct media_entity_operations preview_media_ops = { .link_setup = preview_link_setup, }; +void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) +{ + v4l2_device_unregister_subdev(&prev->subdev); + omap3isp_video_unregister(&prev->video_in); + omap3isp_video_unregister(&prev->video_out); +} + +int omap3isp_preview_register_entities(struct isp_prev_device *prev, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &prev->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&prev->video_in, vdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&prev->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_preview_unregister_entities(prev); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP previewer initialisation and cleanup + */ + /* - * review_init_entities - Initialize subdev and media entity. + * preview_init_entities - Initialize subdev and media entity. * @prev : Pointer to preview structure * return -ENOMEM or zero on success */ @@ -2044,52 +2080,6 @@ static int preview_init_entities(struct isp_prev_device *prev) return 0; } -void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) -{ - v4l2_device_unregister_subdev(&prev->subdev); - omap3isp_video_unregister(&prev->video_in); - omap3isp_video_unregister(&prev->video_out); -} - -int omap3isp_preview_register_entities(struct isp_prev_device *prev, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &prev->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&prev->video_in, vdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&prev->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_preview_unregister_entities(prev); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP previewer initialisation and cleanup - */ - -void omap3isp_preview_cleanup(struct isp_device *isp) -{ - struct isp_prev_device *prev = &isp->isp_prev; - - v4l2_ctrl_handler_free(&prev->ctrls); - omap3isp_video_cleanup(&prev->video_in); - omap3isp_video_cleanup(&prev->video_out); - media_entity_cleanup(&prev->subdev.entity); -} - /* * isp_preview_init - Previewer initialization. * @dev : Pointer to ISP device @@ -2114,3 +2104,13 @@ int omap3isp_preview_init(struct isp_device *isp) return ret; } + +void omap3isp_preview_cleanup(struct isp_device *isp) +{ + struct isp_prev_device *prev = &isp->isp_prev; + + v4l2_ctrl_handler_free(&prev->ctrls); + omap3isp_video_cleanup(&prev->video_in); + omap3isp_video_cleanup(&prev->video_out); + media_entity_cleanup(&prev->subdev.entity); +} diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 78ce0406a232..224b0b90404d 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1608,6 +1608,42 @@ static const struct media_entity_operations resizer_media_ops = { .link_setup = resizer_link_setup, }; +void omap3isp_resizer_unregister_entities(struct isp_res_device *res) +{ + v4l2_device_unregister_subdev(&res->subdev); + omap3isp_video_unregister(&res->video_in); + omap3isp_video_unregister(&res->video_out); +} + +int omap3isp_resizer_register_entities(struct isp_res_device *res, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &res->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&res->video_in, vdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&res->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_resizer_unregister_entities(res); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP resizer initialization and cleanup + */ + /* * resizer_init_entities - Initialize resizer subdev and media entity. * @res : Pointer to resizer device structure @@ -1672,51 +1708,6 @@ static int resizer_init_entities(struct isp_res_device *res) return 0; } -void omap3isp_resizer_unregister_entities(struct isp_res_device *res) -{ - v4l2_device_unregister_subdev(&res->subdev); - omap3isp_video_unregister(&res->video_in); - omap3isp_video_unregister(&res->video_out); -} - -int omap3isp_resizer_register_entities(struct isp_res_device *res, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &res->subdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&res->video_in, vdev); - if (ret < 0) - goto error; - - ret = omap3isp_video_register(&res->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap3isp_resizer_unregister_entities(res); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP resizer initialization and cleanup - */ - -void omap3isp_resizer_cleanup(struct isp_device *isp) -{ - struct isp_res_device *res = &isp->isp_res; - - omap3isp_video_cleanup(&res->video_in); - omap3isp_video_cleanup(&res->video_out); - media_entity_cleanup(&res->subdev.entity); -} - /* * isp_resizer_init - Resizer initialization. * @isp : Pointer to ISP device @@ -1739,3 +1730,12 @@ int omap3isp_resizer_init(struct isp_device *isp) return ret; } + +void omap3isp_resizer_cleanup(struct isp_device *isp) +{ + struct isp_res_device *res = &isp->isp_res; + + omap3isp_video_cleanup(&res->video_in); + omap3isp_video_cleanup(&res->video_out); + media_entity_cleanup(&res->subdev.entity); +} diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index bf0e5a771857..b124326d1e7f 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -1023,24 +1023,6 @@ void omap3isp_stat_dma_isr(struct ispstat *stat) __stat_isr(stat, 1); } -static int isp_stat_init_entities(struct ispstat *stat, const char *name, - const struct v4l2_subdev_ops *sd_ops) -{ - struct v4l2_subdev *subdev = &stat->subdev; - struct media_entity *me = &subdev->entity; - - v4l2_subdev_init(subdev, sd_ops); - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); - subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ - subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - v4l2_set_subdevdata(subdev, stat); - - stat->pad.flags = MEDIA_PAD_FL_SINK; - me->ops = NULL; - - return media_entity_init(me, 1, &stat->pad, 0); -} - int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, struct v4l2_event_subscription *sub) @@ -1071,6 +1053,24 @@ int omap3isp_stat_register_entities(struct ispstat *stat, return v4l2_device_register_subdev(vdev, &stat->subdev); } +static int isp_stat_init_entities(struct ispstat *stat, const char *name, + const struct v4l2_subdev_ops *sd_ops) +{ + struct v4l2_subdev *subdev = &stat->subdev; + struct media_entity *me = &subdev->entity; + + v4l2_subdev_init(subdev, sd_ops); + snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); + subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ + subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; + v4l2_set_subdevdata(subdev, stat); + + stat->pad.flags = MEDIA_PAD_FL_SINK; + me->ops = NULL; + + return media_entity_init(me, 1, &stat->pad, 0); +} + int omap3isp_stat_init(struct ispstat *stat, const char *name, const struct v4l2_subdev_ops *sd_ops) { From ed33ac8e0876a3016511ea0aaf9af1d965ee2c44 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 22 Sep 2011 17:09:26 -0300 Subject: [PATCH 1367/1596] [media] omap3isp: Add missing mutex_destroy() calls Mutexes must be destroyed with mutex_destroy(). Add missing calls in the modules cleanup handlers. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 2 ++ drivers/media/video/omap3isp/ispccdc.c | 2 ++ drivers/media/video/omap3isp/ispstat.c | 1 + drivers/media/video/omap3isp/ispvideo.c | 2 ++ 4 files changed, 7 insertions(+) diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 678e1252047a..c8f147ef320d 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -2210,6 +2210,8 @@ static int isp_probe(struct platform_device *pdev) regulator_put(isp->isp_csiphy2.vdd); regulator_put(isp->isp_csiphy1.vdd); platform_set_drvdata(pdev, NULL); + + mutex_destroy(&isp->isp_mutex); kfree(isp); return ret; diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index c30cc59d7032..3a43be2f5452 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2297,4 +2297,6 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) if (ccdc->fpc.fpcaddr != 0) omap_iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr); + + mutex_destroy(&ccdc->ioctl_lock); } diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index b124326d1e7f..28b7cc61cba6 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -1087,6 +1087,7 @@ int omap3isp_stat_init(struct ispstat *stat, const char *name, void omap3isp_stat_cleanup(struct ispstat *stat) { media_entity_cleanup(&stat->subdev.entity); + mutex_destroy(&stat->ioctl_lock); isp_stat_bufs_free(stat); kfree(stat->buf); } diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 7d74ebbdb63b..d1000723c5ae 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -1328,6 +1328,8 @@ int omap3isp_video_init(struct isp_video *video, const char *name) void omap3isp_video_cleanup(struct isp_video *video) { media_entity_cleanup(&video->video.entity); + mutex_destroy(&video->stream_lock); + mutex_destroy(&video->mutex); } int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) From 9b6390bd95c65ad4a6c650955fa1e3f18f8a540c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 22 Sep 2011 17:10:30 -0300 Subject: [PATCH 1368/1596] [media] omap3isp: Fix memory leaks in initialization error paths Make sure all modules init functions clean up after themselves in case of error. Signed-off-by: Laurent Pinchart Reported-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 19 +++++++++++++--- drivers/media/video/omap3isp/ispccp2.c | 22 ++++++++++-------- drivers/media/video/omap3isp/ispcsi2.c | 15 ++++++++----- drivers/media/video/omap3isp/isppreview.c | 27 +++++++++++------------ drivers/media/video/omap3isp/ispresizer.c | 27 +++++++++++------------ drivers/media/video/omap3isp/ispstat.c | 11 ++++++++- 6 files changed, 74 insertions(+), 47 deletions(-) diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 3a43be2f5452..6330b1d57b1e 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2224,15 +2224,21 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); if (ret < 0) - return ret; + goto error_video; /* Connect the CCDC subdev to the video node. */ ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, &ccdc->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&ccdc->video_out); +error_video: + media_entity_cleanup(me); + return ret; } /* @@ -2246,6 +2252,7 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) int omap3isp_ccdc_init(struct isp_device *isp) { struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + int ret; spin_lock_init(&ccdc->lock); init_waitqueue_head(&ccdc->wait); @@ -2274,7 +2281,13 @@ int omap3isp_ccdc_init(struct isp_device *isp) ccdc->update = OMAP3ISP_CCDC_BLCLAMP; ccdc_apply_controls(ccdc); - return ccdc_init_entities(ccdc); + ret = ccdc_init_entities(ccdc); + if (ret < 0) { + mutex_destroy(&ccdc->ioctl_lock); + return ret; + } + + return 0; } /* diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index 883a2825cb41..904ca8c8b17f 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -1125,15 +1125,21 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); if (ret < 0) - return ret; + goto error_video; /* Connect the video node to the ccp2 subdev. */ ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, &ccp2->subdev.entity, CCP2_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&ccp2->video_in); +error_video: + media_entity_cleanup(&ccp2->subdev.entity); + return ret; } /* @@ -1171,15 +1177,13 @@ int omap3isp_ccp2_init(struct isp_device *isp) } ret = ccp2_init_entities(ccp2); - if (ret < 0) - goto out; + if (ret < 0) { + regulator_put(ccp2->vdds_csib); + return ret; + } ccp2_reset(ccp2); -out: - if (ret) - omap3isp_ccp2_cleanup(isp); - - return ret; + return 0; } /* diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 2c9bffcdc5c9..0c5f1cb9d99d 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -1259,15 +1259,21 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); if (ret < 0) - return ret; + goto error_video; /* Connect the CSI2 subdev to the video node. */ ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, &csi2->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&csi2->video_out); +error_video: + media_entity_cleanup(&csi2->subdev.entity); + return ret; } /* @@ -1289,7 +1295,7 @@ int omap3isp_csi2_init(struct isp_device *isp) ret = csi2_init_entities(csi2a); if (ret < 0) - goto fail; + return ret; if (isp->revision == ISP_REVISION_15_0) { csi2c->isp = isp; @@ -1302,9 +1308,6 @@ int omap3isp_csi2_init(struct isp_device *isp) } return 0; -fail: - omap3isp_csi2_cleanup(isp); - return ret; } /* diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index b926ebbaca3a..b3818356b6f3 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -2060,24 +2060,32 @@ static int preview_init_entities(struct isp_prev_device *prev) ret = omap3isp_video_init(&prev->video_in, "preview"); if (ret < 0) - return ret; + goto error_video_in; ret = omap3isp_video_init(&prev->video_out, "preview"); if (ret < 0) - return ret; + goto error_video_out; /* Connect the video nodes to the previewer subdev. */ ret = media_entity_create_link(&prev->video_in.video.entity, 0, &prev->subdev.entity, PREV_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, &prev->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&prev->video_out); +error_video_out: + omap3isp_video_cleanup(&prev->video_in); +error_video_in: + media_entity_cleanup(&prev->subdev.entity); + return ret; } /* @@ -2088,21 +2096,12 @@ static int preview_init_entities(struct isp_prev_device *prev) int omap3isp_preview_init(struct isp_device *isp) { struct isp_prev_device *prev = &isp->isp_prev; - int ret; spin_lock_init(&prev->lock); init_waitqueue_head(&prev->wait); preview_init_params(prev); - ret = preview_init_entities(prev); - if (ret < 0) - goto out; - -out: - if (ret) - omap3isp_preview_cleanup(isp); - - return ret; + return preview_init_entities(prev); } void omap3isp_preview_cleanup(struct isp_device *isp) diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 224b0b90404d..50e593bfcfaf 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1688,24 +1688,32 @@ static int resizer_init_entities(struct isp_res_device *res) ret = omap3isp_video_init(&res->video_in, "resizer"); if (ret < 0) - return ret; + goto error_video_in; ret = omap3isp_video_init(&res->video_out, "resizer"); if (ret < 0) - return ret; + goto error_video_out; /* Connect the video nodes to the resizer subdev. */ ret = media_entity_create_link(&res->video_in.video.entity, 0, &res->subdev.entity, RESZ_PAD_SINK, 0); if (ret < 0) - return ret; + goto error_link; ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, &res->video_out.video.entity, 0, 0); if (ret < 0) - return ret; + goto error_link; return 0; + +error_link: + omap3isp_video_cleanup(&res->video_out); +error_video_out: + omap3isp_video_cleanup(&res->video_in); +error_video_in: + media_entity_cleanup(&res->subdev.entity); + return ret; } /* @@ -1716,19 +1724,10 @@ static int resizer_init_entities(struct isp_res_device *res) int omap3isp_resizer_init(struct isp_device *isp) { struct isp_res_device *res = &isp->isp_res; - int ret; init_waitqueue_head(&res->wait); atomic_set(&res->stopping, 0); - ret = resizer_init_entities(res); - if (ret < 0) - goto out; - -out: - if (ret) - omap3isp_resizer_cleanup(isp); - - return ret; + return resizer_init_entities(res); } void omap3isp_resizer_cleanup(struct isp_device *isp) diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index 28b7cc61cba6..68d539456c55 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -1074,14 +1074,23 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name, int omap3isp_stat_init(struct ispstat *stat, const char *name, const struct v4l2_subdev_ops *sd_ops) { + int ret; + stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); if (!stat->buf) return -ENOMEM; + isp_stat_buf_clear(stat); mutex_init(&stat->ioctl_lock); atomic_set(&stat->buf_err, 0); - return isp_stat_init_entities(stat, name, sd_ops); + ret = isp_stat_init_entities(stat, name, sd_ops); + if (ret < 0) { + mutex_destroy(&stat->ioctl_lock); + kfree(stat->buf); + } + + return ret; } void omap3isp_stat_cleanup(struct ispstat *stat) From 882cc8539ee73e855a149f99e2166766ce5deb35 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 29 Sep 2011 07:57:00 -0300 Subject: [PATCH 1369/1596] [media] omap3isp: ccdc: remove redundant operation Trivial arithmetics clean up. Signed-off-by: Guennadi Liakhovetski Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 6330b1d57b1e..b0b0fa5a3572 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1836,7 +1836,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, * callers to request an output size bigger than the input size * up to the nearest multiple of 16. */ - fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); + fmt->width = clamp_t(u32, width, 32, fmt->width + 15); fmt->width &= ~15; fmt->height = clamp_t(u32, height, 32, fmt->height); break; From 083eb07854e128a0ed7d79390baae2439755ebdd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 11 Oct 2011 06:34:40 -0300 Subject: [PATCH 1370/1596] [media] omap3isp: Report the ISP revision through the media controller API Set the media_device::hw_revision field to the ISP revision number. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index c8f147ef320d..b818cacf420f 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -1704,6 +1704,7 @@ static int isp_register_entities(struct isp_device *isp) isp->media_dev.dev = isp->dev; strlcpy(isp->media_dev.model, "TI OMAP3 ISP", sizeof(isp->media_dev.model)); + isp->media_dev.hw_revision = isp->revision; isp->media_dev.link_notify = isp_pipeline_link_notify; ret = media_device_register(&isp->media_dev); if (ret < 0) { From e4bc6272ab3f7cb0b56705f78320e361880411e1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Sep 2011 07:54:44 -0300 Subject: [PATCH 1371/1596] [media] omap3isp: preview: Remove horizontal averager support The horizontal averager isn't used and will get in the way when implementing cropping support on the input pad. Remove it, it can be added back later if needed. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isppreview.c | 18 ++---------------- drivers/media/video/omap3isp/isppreview.h | 7 ------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index b3818356b6f3..c920c1e17ae9 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -1228,7 +1228,6 @@ static void preview_init_params(struct isp_prev_device *prev) /* Init values */ params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; - params->average = NO_AVE; params->cfa.format = OMAP3ISP_CFAFMT_BAYER; memcpy(params->cfa.table, cfa_coef_table, sizeof(params->cfa.table)); @@ -1297,7 +1296,6 @@ static void preview_configure(struct isp_prev_device *prev) struct isp_device *isp = to_isp_device(prev); struct v4l2_mbus_framefmt *format; unsigned int max_out_width; - unsigned int format_avg; preview_setup_hw(prev); @@ -1337,8 +1335,7 @@ static void preview_configure(struct isp_prev_device *prev) max_out_width = preview_max_out_width(prev); - format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1); - preview_config_averager(prev, format_avg); + preview_config_averager(prev, 0); preview_config_ycpos(prev, format->code); } @@ -1642,7 +1639,7 @@ static void preview_try_format(struct isp_prev_device *prev, */ if (prev->input == PREVIEW_INPUT_MEMORY) { fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, - max_out_width * 8); + max_out_width); fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, PREV_MAX_HEIGHT); } @@ -1689,17 +1686,6 @@ static void preview_try_format(struct isp_prev_device *prev, if (prev->input == PREVIEW_INPUT_CCDC) fmt->width -= 4; - /* The preview module can output a maximum of 3312 pixels - * horizontally due to fixed memory-line sizes. Compute the - * horizontal averaging factor accordingly. Note that the limit - * applies to the noise filter and CFA interpolation blocks, so - * it doesn't take cropping by further blocks into account. - * - * ES 1.0 hardware revision is limited to 1280 pixels - * horizontally. - */ - fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1); - /* Assume that all blocks are enabled and crop pixels and lines * accordingly. See preview_config_input_size() for more * information. diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index fa943bd05c7f..272a44a2b9bc 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h @@ -45,11 +45,6 @@ #define ISPPRV_CONTRAST_HIGH 0xFF #define ISPPRV_CONTRAST_UNITS 0x1 -#define NO_AVE 0x0 -#define AVE_2_PIX 0x1 -#define AVE_4_PIX 0x2 -#define AVE_8_PIX 0x3 - /* Features list */ #define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH #define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW @@ -106,7 +101,6 @@ enum preview_ycpos_mode { * @rgb2ycbcr: RGB to ycbcr parameters. * @hmed: Horizontal median filter. * @yclimit: YC limits parameters. - * @average: Downsampling rate for averager. * @contrast: Contrast. * @brightness: Brightness. */ @@ -124,7 +118,6 @@ struct prev_params { struct omap3isp_prev_csc rgb2ycbcr; struct omap3isp_prev_hmed hmed; struct omap3isp_prev_yclimit yclimit; - u8 average; u8 contrast; u8 brightness; }; From 059dc1d9841f061e5767b95822fb4035ad7559fc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 3 Oct 2011 07:56:15 -0300 Subject: [PATCH 1372/1596] [media] omap3isp: preview: Rename min/max input/output sizes defines The macros that define the minimum/maximum input and output sizes are defined in seperate files and have no consistent naming. In preparation for preview engine cropping support, move them all to isppreview.c and rename them to PREV_{MIN|MAX}_{IN|OUT}_{WIDTH|HEIGHT}*. Remove unused and/or unneeded local variables that store the maximum output width. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isppreview.c | 33 ++++++++++++----------- drivers/media/video/omap3isp/ispreg.h | 3 --- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index c920c1e17ae9..d5cce423283c 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -76,9 +76,15 @@ static struct omap3isp_prev_csc flr_prev_csc = { #define DEF_DETECT_CORRECT_VAL 0xe -#define PREV_MIN_WIDTH 64 -#define PREV_MIN_HEIGHT 8 -#define PREV_MAX_HEIGHT 16384 +#define PREV_MIN_IN_WIDTH 64 +#define PREV_MIN_IN_HEIGHT 8 +#define PREV_MAX_IN_HEIGHT 16384 + +#define PREV_MIN_OUT_WIDTH 0 +#define PREV_MIN_OUT_HEIGHT 0 +#define PREV_MAX_OUT_WIDTH 1280 +#define PREV_MAX_OUT_WIDTH_ES2 3300 +#define PREV_MAX_OUT_WIDTH_3630 4096 /* * Coeficient Tables for the submodules in Preview. @@ -1280,14 +1286,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) switch (isp->revision) { case ISP_REVISION_1_0: - return ISPPRV_MAXOUTPUT_WIDTH; + return PREV_MAX_OUT_WIDTH; case ISP_REVISION_2_0: default: - return ISPPRV_MAXOUTPUT_WIDTH_ES2; + return PREV_MAX_OUT_WIDTH_ES2; case ISP_REVISION_15_0: - return ISPPRV_MAXOUTPUT_WIDTH_3630; + return PREV_MAX_OUT_WIDTH_3630; } } @@ -1295,7 +1301,6 @@ static void preview_configure(struct isp_prev_device *prev) { struct isp_device *isp = to_isp_device(prev); struct v4l2_mbus_framefmt *format; - unsigned int max_out_width; preview_setup_hw(prev); @@ -1333,8 +1338,6 @@ static void preview_configure(struct isp_prev_device *prev) preview_config_outlineoffset(prev, ALIGN(format->width, 0x10) * 2); - max_out_width = preview_max_out_width(prev); - preview_config_averager(prev, 0); preview_config_ycpos(prev, format->code); } @@ -1620,12 +1623,9 @@ static void preview_try_format(struct isp_prev_device *prev, enum v4l2_subdev_format_whence which) { struct v4l2_mbus_framefmt *format; - unsigned int max_out_width; enum v4l2_mbus_pixelcode pixelcode; unsigned int i; - max_out_width = preview_max_out_width(prev); - switch (pad) { case PREV_PAD_SINK: /* When reading data from the CCDC, the input size has already @@ -1638,10 +1638,11 @@ static void preview_try_format(struct isp_prev_device *prev, * filter array interpolation. */ if (prev->input == PREVIEW_INPUT_MEMORY) { - fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, - max_out_width); - fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, - PREV_MAX_HEIGHT); + fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH, + preview_max_out_width(prev)); + fmt->height = clamp_t(u32, fmt->height, + PREV_MIN_IN_HEIGHT, + PREV_MAX_IN_HEIGHT); } fmt->colorspace = V4L2_COLORSPACE_SRGB; diff --git a/drivers/media/video/omap3isp/ispreg.h b/drivers/media/video/omap3isp/ispreg.h index 69f6af6f6b9c..084ea77d65a7 100644 --- a/drivers/media/video/omap3isp/ispreg.h +++ b/drivers/media/video/omap3isp/ispreg.h @@ -402,9 +402,6 @@ #define ISPPRV_YENH_TABLE_ADDR 0x1000 #define ISPPRV_CFA_TABLE_ADDR 0x1400 -#define ISPPRV_MAXOUTPUT_WIDTH 1280 -#define ISPPRV_MAXOUTPUT_WIDTH_ES2 3300 -#define ISPPRV_MAXOUTPUT_WIDTH_3630 4096 #define ISPRSZ_MIN_OUTPUT 64 #define ISPRSZ_MAX_OUTPUT 3312 From 1f69fd970dfdd9872c83f62864b2557d686948cb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 21 Sep 2011 20:05:45 -0300 Subject: [PATCH 1373/1596] [media] omap3isp: preview: Add crop support on the sink pad The crop rectangle takes the preview engine internal cropping requirements into account. The smallest allowable margins are 14 columns and 8 rows when reading from memory, and 18 columns and 8 rows when processing data on the fly from the CCDC. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isppreview.c | 262 ++++++++++++++++------ drivers/media/video/omap3isp/isppreview.h | 2 + 2 files changed, 198 insertions(+), 66 deletions(-) diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index d5cce423283c..ccb876fe023f 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -76,6 +76,42 @@ static struct omap3isp_prev_csc flr_prev_csc = { #define DEF_DETECT_CORRECT_VAL 0xe +/* + * Margins and image size limits. + * + * The preview engine crops several rows and columns internally depending on + * which filters are enabled. To avoid format changes when the filters are + * enabled or disabled (which would prevent them from being turned on or off + * during streaming), the driver assumes all the filters are enabled when + * computing sink crop and source format limits. + * + * If a filter is disabled, additional cropping is automatically added at the + * preview engine input by the driver to avoid overflow at line and frame end. + * This is completely transparent for applications. + * + * Median filter 4 pixels + * Noise filter, + * Faulty pixels correction 4 pixels, 4 lines + * CFA filter 4 pixels, 4 lines in Bayer mode + * 2 lines in other modes + * Color suppression 2 pixels + * or luma enhancement + * ------------------------------------------------------------- + * Maximum total 14 pixels, 8 lines + * + * The color suppression and luma enhancement filters are applied after bayer to + * YUV conversion. They thus can crop one pixel on the left and one pixel on the + * right side of the image without changing the color pattern. When both those + * filters are disabled, the driver must crop the two pixels on the same side of + * the image to avoid changing the bayer pattern. The left margin is thus set to + * 8 pixels and the right margin to 6 pixels. + */ + +#define PREV_MARGIN_LEFT 8 +#define PREV_MARGIN_RIGHT 6 +#define PREV_MARGIN_TOP 4 +#define PREV_MARGIN_BOTTOM 4 + #define PREV_MIN_IN_WIDTH 64 #define PREV_MIN_IN_HEIGHT 8 #define PREV_MAX_IN_HEIGHT 16384 @@ -985,52 +1021,36 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average) * enabled when reporting source pad formats to userspace. If this assumption is * not true, rows and columns must be manually cropped at the preview engine * input to avoid overflows at the end of lines and frames. + * + * See the explanation at the PREV_MARGIN_* definitions for more details. */ static void preview_config_input_size(struct isp_prev_device *prev) { struct isp_device *isp = to_isp_device(prev); struct prev_params *params = &prev->params; - struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; - unsigned int sph = 0; - unsigned int eph = format->width - 1; - unsigned int slv = 0; - unsigned int elv = format->height - 1; - - if (prev->input == PREVIEW_INPUT_CCDC) { - sph += 2; - eph -= 2; - } - - /* - * Median filter 4 pixels - * Noise filter 4 pixels, 4 lines - * or faulty pixels correction - * CFA filter 4 pixels, 4 lines in Bayer mode - * 2 lines in other modes - * Color suppression 2 pixels - * or luma enhancement - * ------------------------------------------------------------- - * Maximum total 14 pixels, 8 lines - */ - - if (!(params->features & PREV_CFA)) { - sph += 2; - eph -= 2; - slv += 2; - elv -= 2; + unsigned int sph = prev->crop.left; + unsigned int eph = prev->crop.left + prev->crop.width - 1; + unsigned int slv = prev->crop.top; + unsigned int elv = prev->crop.top + prev->crop.height - 1; + + if (params->features & PREV_CFA) { + sph -= 2; + eph += 2; + slv -= 2; + elv += 2; } - if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) { - sph += 2; - eph -= 2; - slv += 2; - elv -= 2; + if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) { + sph -= 2; + eph += 2; + slv -= 2; + elv += 2; } - if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) { - sph += 2; - eph -= 2; + if (params->features & PREV_HORZ_MEDIAN_FILTER) { + sph -= 2; + eph += 2; } - if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))) - sph += 2; + if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)) + sph -= 2; isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); @@ -1597,6 +1617,16 @@ __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, return &prev->formats[pad]; } +static struct v4l2_rect * +__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); + else + return &prev->crop; +} + /* previewer format descriptions */ static const unsigned int preview_input_fmts[] = { V4L2_MBUS_FMT_SGRBG10_1X10, @@ -1611,19 +1641,23 @@ static const unsigned int preview_output_fmts[] = { }; /* - * preview_try_format - Handle try format by pad subdev method - * @prev: ISP preview device - * @fh : V4L2 subdev file handle - * @pad: pad num - * @fmt: pointer to v4l2 format structure + * preview_try_format - Validate a format + * @prev: ISP preview engine + * @fh: V4L2 subdev file handle + * @pad: pad number + * @fmt: format to be validated + * @which: try/active format selector + * + * Validate and adjust the given format for the given pad based on the preview + * engine limits and the format and crop rectangles on other pads. */ static void preview_try_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { - struct v4l2_mbus_framefmt *format; enum v4l2_mbus_pixelcode pixelcode; + struct v4l2_rect *crop; unsigned int i; switch (pad) { @@ -1659,15 +1693,8 @@ static void preview_try_format(struct isp_prev_device *prev, case PREV_PAD_SOURCE: pixelcode = fmt->code; - format = __preview_get_format(prev, fh, PREV_PAD_SINK, which); - memcpy(fmt, format, sizeof(*fmt)); + *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); - /* The preview module output size is configurable through the - * input interface (horizontal and vertical cropping) and the - * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In - * spite of this, hardcode the output size to the biggest - * possible value for simplicity reasons. - */ switch (pixelcode) { case V4L2_MBUS_FMT_YUYV8_1X16: case V4L2_MBUS_FMT_UYVY8_1X16: @@ -1679,20 +1706,14 @@ static void preview_try_format(struct isp_prev_device *prev, break; } - /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped - * from the left and right sides when the input source is the - * CCDC. This seems not to be needed in practice, investigation - * is required. - */ - if (prev->input == PREVIEW_INPUT_CCDC) - fmt->width -= 4; - - /* Assume that all blocks are enabled and crop pixels and lines - * accordingly. See preview_config_input_size() for more - * information. + /* The preview module output size is configurable through the + * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This + * is not supported yet, hardcode the output size to the crop + * rectangle size. */ - fmt->width -= 14; - fmt->height -= 8; + crop = __preview_get_crop(prev, fh, which); + fmt->width = crop->width; + fmt->height = crop->height; fmt->colorspace = V4L2_COLORSPACE_JPEG; break; @@ -1701,6 +1722,49 @@ static void preview_try_format(struct isp_prev_device *prev, fmt->field = V4L2_FIELD_NONE; } +/* + * preview_try_crop - Validate a crop rectangle + * @prev: ISP preview engine + * @sink: format on the sink pad + * @crop: crop rectangle to be validated + * + * The preview engine crops lines and columns for its internal operation, + * depending on which filters are enabled. Enforce minimum crop margins to + * handle that transparently for userspace. + * + * See the explanation at the PREV_MARGIN_* definitions for more details. + */ +static void preview_try_crop(struct isp_prev_device *prev, + const struct v4l2_mbus_framefmt *sink, + struct v4l2_rect *crop) +{ + unsigned int left = PREV_MARGIN_LEFT; + unsigned int right = sink->width - PREV_MARGIN_RIGHT; + unsigned int top = PREV_MARGIN_TOP; + unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM; + + /* When processing data on-the-fly from the CCDC, at least 2 pixels must + * be cropped from the left and right sides of the image. As we don't + * know which filters will be enabled, increase the left and right + * margins by two. + */ + if (prev->input == PREVIEW_INPUT_CCDC) { + left += 2; + right -= 2; + } + + /* Restrict left/top to even values to keep the Bayer pattern. */ + crop->left &= ~1; + crop->top &= ~1; + + crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH); + crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT); + crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH, + right - crop->left); + crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT, + bottom - crop->top); +} + /* * preview_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure @@ -1762,6 +1826,60 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, return 0; } +/* + * preview_get_crop - Retrieve the crop rectangle on a pad + * @sd: ISP preview V4L2 subdevice + * @fh: V4L2 subdev file handle + * @crop: crop rectangle + * + * Return 0 on success or a negative error code otherwise. + */ +static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + + /* Cropping is only supported on the sink pad. */ + if (crop->pad != PREV_PAD_SINK) + return -EINVAL; + + crop->rect = *__preview_get_crop(prev, fh, crop->which); + return 0; +} + +/* + * preview_set_crop - Retrieve the crop rectangle on a pad + * @sd: ISP preview V4L2 subdevice + * @fh: V4L2 subdev file handle + * @crop: crop rectangle + * + * Return 0 on success or a negative error code otherwise. + */ +static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + /* Cropping is only supported on the sink pad. */ + if (crop->pad != PREV_PAD_SINK) + return -EINVAL; + + /* The crop rectangle can't be changed while streaming. */ + if (prev->state != ISP_PIPELINE_STREAM_STOPPED) + return -EBUSY; + + format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which); + preview_try_crop(prev, format, &crop->rect); + *__preview_get_crop(prev, fh, crop->which) = crop->rect; + + /* Update the source format. */ + format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which); + preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which); + + return 0; +} + /* * preview_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure @@ -1795,6 +1913,7 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; format = __preview_get_format(prev, fh, fmt->pad, fmt->which); if (format == NULL) @@ -1805,9 +1924,18 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* Propagate the format from sink to source */ if (fmt->pad == PREV_PAD_SINK) { + /* Reset the crop rectangle. */ + crop = __preview_get_crop(prev, fh, fmt->which); + crop->left = 0; + crop->top = 0; + crop->width = fmt->format.width; + crop->height = fmt->format.height; + + preview_try_crop(prev, &fmt->format, crop); + + /* Update the source format. */ format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, fmt->which); - *format = fmt->format; preview_try_format(prev, fh, PREV_PAD_SOURCE, format, fmt->which); } @@ -1856,6 +1984,8 @@ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { .enum_frame_size = preview_enum_frame_size, .get_fmt = preview_get_format, .set_fmt = preview_set_format, + .get_crop = preview_get_crop, + .set_crop = preview_set_crop, }; /* subdev operations */ diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index 272a44a2b9bc..f54e775c2df4 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h @@ -152,6 +152,7 @@ struct isptables_update { * @subdev: V4L2 subdevice * @pads: Media entity pads * @formats: Active formats at the subdev pad + * @crop: Active crop rectangle * @input: Module currently connected to the input pad * @output: Bitmask of the active output * @video_in: Input video entity @@ -170,6 +171,7 @@ struct isp_prev_device { struct v4l2_subdev subdev; struct media_pad pads[PREV_PADS_NUM]; struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; + struct v4l2_rect crop; struct v4l2_ctrl_handler ctrls; From 94f3f48f90f77e3bfcafce9b259086cfebcd166d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 20 Jan 2011 21:15:42 -0300 Subject: [PATCH 1374/1596] [media] omap_vout: Add poll() support Signed-off-by: Laurent Pinchart Acked-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap/omap_vout.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 30d8896bb710..9c5c19f142de 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -833,6 +833,15 @@ static void omap_vout_buffer_release(struct videobuf_queue *q, /* * File operations */ +static unsigned int omap_vout_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct omap_vout_device *vout = file->private_data; + struct videobuf_queue *q = &vout->vbq; + + return videobuf_poll_stream(file, q, wait); +} + static void omap_vout_vm_open(struct vm_area_struct *vma) { struct omap_vout_device *vout = vma->vm_private_data; @@ -1861,6 +1870,7 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = { static const struct v4l2_file_operations omap_vout_fops = { .owner = THIS_MODULE, + .poll = omap_vout_poll, .unlocked_ioctl = video_ioctl2, .mmap = omap_vout_mmap, .open = omap_vout_open, From 8c4343e5909f956140229b0d960dc7a9c4fd4bdd Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Wed, 12 Oct 2011 17:51:22 -0300 Subject: [PATCH 1375/1596] [media] media: tea5764: reconcile Kconfig symbol and macro The Kconfig symbol RADIO_TEA5764_XTAL is unused. The code does use a RADIO_TEA5764_XTAL macro, but does that rather peculiar. But there seems to be a way to keep both. (The easiest way out would be to rip out both the Kconfig symbol and the macro.) Note there's also a module parameter 'use_xtal' to influence all this. Signed-off-by: Paul Bolle Acked-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-tea5764.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 95ddcc4845d3..db20904d01f0 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -128,8 +128,10 @@ struct tea5764_write_regs { u16 rdsbbl; /* PAUSEDET & RDSBBL */ } __attribute__ ((packed)); -#ifndef RADIO_TEA5764_XTAL +#ifdef CONFIG_RADIO_TEA5764_XTAL #define RADIO_TEA5764_XTAL 1 +#else +#define RADIO_TEA5764_XTAL 0 #endif static int radio_nr = -1; From 567a23f4389f86c10355ae89909d6d87f312d1a0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Oct 2011 02:41:41 -0300 Subject: [PATCH 1376/1596] [media] cx25821: off by one in cx25821_vidioc_s_input() If "i" is 2 then when we call cx25821_video_mux() we'd end up going past the end of the cx25821_boards[dev->board]->input[]. The INPUT() macro obfuscates what's going on in that function so it's a bit hard to follow. And as Mauro points out the hard coded 2 is not very helpful. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25821/cx25821-video.c | 2 +- drivers/media/video/cx25821/cx25821.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c index 084fc0899e13..4d6907cda75b 100644 --- a/drivers/media/video/cx25821/cx25821-video.c +++ b/drivers/media/video/cx25821/cx25821-video.c @@ -1312,7 +1312,7 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) return err; } - if (i > 2) { + if (i >= CX25821_NR_INPUT) { dprintk(1, "%s(): -EINVAL\n", __func__); return -EINVAL; } diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h index db2615b2bac3..2d2d00932823 100644 --- a/drivers/media/video/cx25821/cx25821.h +++ b/drivers/media/video/cx25821/cx25821.h @@ -98,6 +98,7 @@ #define CX25821_BOARD_CONEXANT_ATHENA10 1 #define MAX_VID_CHANNEL_NUM 12 #define VID_CHANNEL_NUM 8 +#define CX25821_NR_INPUT 2 struct cx25821_fmt { char *name; @@ -196,7 +197,7 @@ struct cx25821_board { unsigned char radio_addr; u32 clk_freq; - struct cx25821_input input[2]; + struct cx25821_input input[CX25821_NR_INPUT]; }; struct cx25821_subid { From efabaaf38a6cac929650943151e679f2b5cdae8b Mon Sep 17 00:00:00 2001 From: Teka Date: Fri, 14 Oct 2011 05:40:29 -0300 Subject: [PATCH 1377/1596] [media] Support for Terratec G1 Hi, This is a little patch to support Terratec G1 (based on Terratec Grabby). It works perfectly on my pc (Ubuntu 11.04 / Kernel 2.6.38). Best regards, Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4240f0b720fa..9b747c266afa 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1923,6 +1923,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2860_BOARD_TERRATEC_AV350 }, { USB_DEVICE(0x0ccd, 0x0096), .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, + { USB_DEVICE(0x0ccd, 0x10AF), + .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x0fd9, 0x0033), .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, { USB_DEVICE(0x185b, 0x2870), From bc54919f83df61860c7a183016bbced054f9e474 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Fri, 14 Oct 2011 19:54:11 -0300 Subject: [PATCH 1378/1596] [media] it913x [VER 1.07] Support for single ITE 9135 devices Support for single ITE 9135 device. Only single devices have been tested. Dual ITE 9135 devices should work, but have not been tested. TODOs support for ver 2 chip config for other tuner types. rework of firmware file. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 + drivers/media/dvb/dvb-usb/it913x.c | 105 ++++++++++++++++++------ 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2ad33ba92ba2..2d08c9b5128a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -37,6 +37,7 @@ #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 #define USB_VID_INTEL 0x8086 +#define USB_VID_ITETECH 0x048d #define USB_VID_KWORLD 0xeb2a #define USB_VID_KWORLD_2 0x1b80 #define USB_VID_KYE 0x0458 @@ -126,6 +127,7 @@ #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_INTEL_CE9500 0x9500 +#define USB_PID_ITETECH_IT9135 0x9135 #define USB_PID_KWORLD_399U 0xe399 #define USB_PID_KWORLD_399U_2 0xe400 #define USB_PID_KWORLD_395U 0xe396 diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index f027a2c1c3e8..c46226187143 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -60,6 +60,17 @@ struct it913x_state { u8 id; }; +struct ite_config { + u8 chip_ver; + u16 chip_type; + u32 firmware; + u8 tuner_id_0; + u8 tuner_id_1; + u8 dual_mode; +}; + +struct ite_config it913x_config; + static int it913x_bulk_write(struct usb_device *dev, u8 *snd, int len, u8 pipe) { @@ -191,18 +202,23 @@ static int it913x_read_reg(struct usb_device *udev, u32 reg) static u32 it913x_query(struct usb_device *udev, u8 pro) { int ret; - u32 res = 0; u8 data[4]; ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, - 0x1222, 0, &data[0], 1); - if (data[0] == 0x1) { - ret = it913x_io(udev, READ_SHORT, pro, + 0x1222, 0, &data[0], 3); + + it913x_config.chip_ver = data[0]; + it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; + + info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver, + it913x_config.chip_type); + + ret |= it913x_io(udev, READ_SHORT, pro, CMD_QUERYINFO, 0, 0x1, &data[0], 4); - res = (data[0] << 24) + (data[1] << 16) + + + it913x_config.firmware = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; - } - return (ret < 0) ? 0 : res; + return (ret < 0) ? 0 : it913x_config.firmware; } static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) @@ -336,26 +352,35 @@ static int it913x_identify_state(struct usb_device *udev, int *cold) { int ret = 0, firm_no; - u8 reg, adap, ep, tun0, tun1; + u8 reg, remote; firm_no = it913x_return_status(udev); - ep = it913x_read_reg(udev, 0x49ac); - adap = it913x_read_reg(udev, 0x49c5); - tun0 = it913x_read_reg(udev, 0x49d0); - info("No. Adapters=%x Endpoints=%x Tuner Type=%x", adap, ep, tun0); + /* checnk for dual mode */ + it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); + + /* TODO different remotes */ + remote = it913x_read_reg(udev, 0x49ac); /* Remote */ + if (remote == 0) + props->rc.core.rc_codes = NULL; + + /* TODO at the moment tuner_id is always assigned to 0x38 */ + it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0); + + info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode + , remote, it913x_config.tuner_id_0); if (firm_no > 0) { *cold = 0; return 0; } - if (adap > 2) { - tun1 = it913x_read_reg(udev, 0x49e0); + if (it913x_config.dual_mode) { + it913x_config.tuner_id_1 = it913x_read_reg(udev, 0x49e0); ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1); ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1); ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1); - msleep(50); /* Delay noticed reset cycle ? */ + msleep(50); ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); msleep(50); reg = it913x_read_reg(udev, GPIOH1_O); @@ -366,14 +391,19 @@ static int it913x_identify_state(struct usb_device *udev, ret = it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); } + props->num_adapters = 2; } else props->num_adapters = 1; reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); - ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); - - ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); + if (it913x_config.dual_mode) { + ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); + } else { + ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0); + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0); + } *cold = 1; @@ -403,13 +433,11 @@ static int it913x_download_firmware(struct usb_device *udev, const struct firmware *fw) { int ret = 0, i; - u8 packet_size, dlen, tun1; + u8 packet_size, dlen; u8 *fw_data; packet_size = 0x29; - tun1 = it913x_read_reg(udev, 0x49e0); - ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); info("FRM Starting Firmware Download"); @@ -444,11 +472,12 @@ static int it913x_download_firmware(struct usb_device *udev, ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); /* Tuner function */ - ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); + if (it913x_config.dual_mode) + ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); - if (tun1 > 0) { + if (it913x_config.dual_mode) { ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); } @@ -475,9 +504,28 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; + u8 tuner_id, tuner_type; + + if (adap->id == 0) + tuner_id = it913x_config.tuner_id_0; + else + tuner_id = it913x_config.tuner_id_1; + + /* TODO we always use IT9137 possible references here*/ + /* Documentation suggests don't care */ + switch (tuner_id) { + case 0x51: + case 0x52: + case 0x60: + case 0x61: + case 0x62: + default: + case 0x38: + tuner_type = IT9137; + } adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, - &adap->dev->i2c_adap, adap_addr, adf, IT9137); + &adap->dev->i2c_adap, adap_addr, adf, tuner_type); if (adap->id == 0 && adap->fe_adap[0].fe) { ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); @@ -533,6 +581,7 @@ static int it913x_probe(struct usb_interface *intf, static struct usb_device_id it913x_table[] = { { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, + { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) }, {} /* Terminating entry */ }; @@ -608,12 +657,14 @@ static struct dvb_usb_device_properties it913x_properties = { .rc_codes = RC_MAP_KWORLD_315U, }, .i2c_algo = &it913x_i2c_algo, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { { "Kworld UB499-2T T09(IT9137)", { &it913x_table[0], NULL }, }, - + { "ITE 9135 Generic", + { &it913x_table[1], NULL }, + }, } }; @@ -647,5 +698,5 @@ module_exit(it913x_module_exit); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("it913x USB 2 Driver"); -MODULE_VERSION("1.06"); +MODULE_VERSION("1.07"); MODULE_LICENSE("GPL"); From b3f4e1eba45eda5d1213810ef3bc53e5247df2df Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Tue, 18 Oct 2011 15:37:36 -0300 Subject: [PATCH 1379/1596] [media] saa7134.h: Suppress compiler warnings when CONFIG_VIDEO_SAA7134_RC is not set If the said config optio is not set, the compiler will spill out many warnings about statements with no effect, such as: Casting the zero to void will cure the warning. Signed-off-by: Timo Kokkonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index bc8d6bba8ee5..9b550687213a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -843,10 +843,10 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev); int saa7134_ir_start(struct saa7134_dev *dev); void saa7134_ir_stop(struct saa7134_dev *dev); #else -#define saa7134_input_init1(dev) (0) -#define saa7134_input_fini(dev) (0) -#define saa7134_input_irq(dev) (0) -#define saa7134_probe_i2c_ir(dev) (0) -#define saa7134_ir_start(dev) (0) -#define saa7134_ir_stop(dev) (0) +#define saa7134_input_init1(dev) ((void)0) +#define saa7134_input_fini(dev) ((void)0) +#define saa7134_input_irq(dev) ((void)0) +#define saa7134_probe_i2c_ir(dev) ((void)0) +#define saa7134_ir_start(dev) ((void)0) +#define saa7134_ir_stop(dev) ((void)0) #endif From 303f59d1a71ebf1ede04b2adb07e3f545e53b7ba Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 2 Nov 2011 22:07:29 -0700 Subject: [PATCH 1380/1596] dt/platform: minor cleanup * Correct description of of_platform_bus_create to match implementation * Remove a level of indentation in of_dev_lookup Signed-off-by: Olof Johansson Acked-by: Grant Likely Signed-off-by: Rob Herring --- drivers/of/platform.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index ed5a6d3c26aa..cbd5d701c7e0 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -310,18 +310,21 @@ static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *l struct device_node *np) { struct resource res; - if (lookup) { - for(; lookup->name != NULL; lookup++) { - if (!of_device_is_compatible(np, lookup->compatible)) - continue; - if (of_address_to_resource(np, 0, &res)) - continue; - if (res.start != lookup->phys_addr) - continue; - pr_debug("%s: devname=%s\n", np->full_name, lookup->name); - return lookup; - } + + if (!lookup) + return NULL; + + for(; lookup->name != NULL; lookup++) { + if (!of_device_is_compatible(np, lookup->compatible)) + continue; + if (of_address_to_resource(np, 0, &res)) + continue; + if (res.start != lookup->phys_addr) + continue; + pr_debug("%s: devname=%s\n", np->full_name, lookup->name); + return lookup; } + return NULL; } @@ -329,8 +332,9 @@ static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *l * of_platform_bus_create() - Create a device for a node and its children. * @bus: device node of the bus to instantiate * @matches: match table for bus nodes - * disallow recursive creation of child buses + * @lookup: auxdata table for matching id and platform_data with device nodes * @parent: parent for new device, or NULL for top level. + * @strict: require compatible property * * Creates a platform_device for the provided device_node, and optionally * recursively create devices for all the child nodes. From 02aac316abf436a7529d46a71f7083f9f9ef4b49 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 3 Nov 2010 21:04:59 -0500 Subject: [PATCH 1381/1596] ahci: add DT binding for Calxeda AHCI controller Add devicetree match table to ahci platform driver for Calxeda Highbank AHCI controller. Signed-off-by: Rob Herring Acked-by: Grant Likely Cc: Jeff Garzik Cc: linux-ide@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: devicetree-discuss@lists.ozlabs.org --- .../devicetree/bindings/ata/calxeda-sata.txt | 17 +++++++++++++++++ drivers/ata/ahci_platform.c | 7 +++++++ 2 files changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/ata/calxeda-sata.txt diff --git a/Documentation/devicetree/bindings/ata/calxeda-sata.txt b/Documentation/devicetree/bindings/ata/calxeda-sata.txt new file mode 100644 index 000000000000..79caa5651f53 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/calxeda-sata.txt @@ -0,0 +1,17 @@ +* Calxeda SATA Controller + +SATA nodes are defined to describe on-chip Serial ATA controllers. +Each SATA controller should have its own node. + +Required properties: +- compatible : compatible list, contains "calxeda,hb-ahci" +- interrupts : +- reg : + +Example: + sata@ffe08000 { + compatible = "calxeda,hb-ahci"; + reg = <0xffe08000 0x1000>; + interrupts = <115>; + }; + diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index c03277d37748..004f2ce3dc73 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -202,11 +202,18 @@ static int __devexit ahci_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id ahci_of_match[] = { + { .compatible = "calxeda,hb-ahci", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ahci_of_match); + static struct platform_driver ahci_driver = { .remove = __devexit_p(ahci_remove), .driver = { .name = "ahci", .owner = THIS_MODULE, + .of_match_table = ahci_of_match, }, .id_table = ahci_devtype, }; From e0b1f39d55864547242b4e4edb86d737bca3a249 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 2 Nov 2011 22:19:25 -0400 Subject: [PATCH 1382/1596] arch/tile: avoid ISO namespace pollution with is used by glibc's from , which means that it can't clutter the namespace with random symbols or #defines. However, we use to get a suitable type to hold a machine register. This change makes safe to use in this kind of context if __need_int_reg_t is defined prior to including the file; in that case, it only defines a few symbols that are safe in the ISO namespace (prefixed with double underscores). then uses the __uint_reg_t type instead of the normal uint_reg_t. Signed-off-by: Chris Metcalf --- arch/tile/include/arch/abi.h | 99 ++++++++++++++++++++++-------- arch/tile/include/asm/sigcontext.h | 18 +++--- 2 files changed, 82 insertions(+), 35 deletions(-) diff --git a/arch/tile/include/arch/abi.h b/arch/tile/include/arch/abi.h index 8affc76f771a..c55a3d432644 100644 --- a/arch/tile/include/arch/abi.h +++ b/arch/tile/include/arch/abi.h @@ -15,13 +15,78 @@ /** * @file * - * ABI-related register definitions helpful when writing assembly code. + * ABI-related register definitions. */ #ifndef __ARCH_ABI_H__ -#define __ARCH_ABI_H__ -#include +#if !defined __need_int_reg_t && !defined __DOXYGEN__ +# define __ARCH_ABI_H__ +# include +#endif + +/* Provide the basic machine types. */ +#ifndef __INT_REG_BITS + +/** Number of bits in a register. */ +#if defined __tilegx__ +# define __INT_REG_BITS 64 +#elif defined __tilepro__ +# define __INT_REG_BITS 32 +#elif !defined __need_int_reg_t +# include +# define __INT_REG_BITS CHIP_WORD_SIZE() +#else +# error Unrecognized architecture with __need_int_reg_t +#endif + +#if __INT_REG_BITS == 64 + +#ifndef __ASSEMBLER__ +/** Unsigned type that can hold a register. */ +typedef unsigned long long __uint_reg_t; + +/** Signed type that can hold a register. */ +typedef long long __int_reg_t; +#endif + +/** String prefix to use for printf(). */ +#define __INT_REG_FMT "ll" + +#else + +#ifndef __ASSEMBLER__ +/** Unsigned type that can hold a register. */ +typedef unsigned long __uint_reg_t; + +/** Signed type that can hold a register. */ +typedef long __int_reg_t; +#endif + +/** String prefix to use for printf(). */ +#define __INT_REG_FMT "l" + +#endif +#endif /* __INT_REG_BITS */ + + +#ifndef __need_int_reg_t + + +#ifndef __ASSEMBLER__ +/** Unsigned type that can hold a register. */ +typedef __uint_reg_t uint_reg_t; + +/** Signed type that can hold a register. */ +typedef __int_reg_t int_reg_t; +#endif + +/** String prefix to use for printf(). */ +#define INT_REG_FMT __INT_REG_FMT + +/** Number of bits in a register. */ +#define INT_REG_BITS __INT_REG_BITS + /* Registers 0 - 55 are "normal", but some perform special roles. */ @@ -59,7 +124,7 @@ * The ABI requires callers to allocate a caller state save area of * this many bytes at the bottom of each stack frame. */ -#define C_ABI_SAVE_AREA_SIZE (2 * (CHIP_WORD_SIZE() / 8)) +#define C_ABI_SAVE_AREA_SIZE (2 * (INT_REG_BITS / 8)) /** * The operand to an 'info' opcode directing the backtracer to not @@ -67,30 +132,10 @@ */ #define INFO_OP_CANNOT_BACKTRACE 2 -#ifndef __ASSEMBLER__ -#if CHIP_WORD_SIZE() > 32 -/** Unsigned type that can hold a register. */ -typedef unsigned long long uint_reg_t; +#endif /* !__need_int_reg_t */ -/** Signed type that can hold a register. */ -typedef long long int_reg_t; - -/** String prefix to use for printf(). */ -#define INT_REG_FMT "ll" - -#elif !defined(__LP64__) /* avoid confusion with LP64 cross-build tools */ - -/** Unsigned type that can hold a register. */ -typedef unsigned long uint_reg_t; - -/** Signed type that can hold a register. */ -typedef long int_reg_t; - -/** String prefix to use for printf(). */ -#define INT_REG_FMT "l" - -#endif -#endif /* __ASSEMBLER__ */ +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_int_reg_t #endif /* !__ARCH_ABI_H__ */ diff --git a/arch/tile/include/asm/sigcontext.h b/arch/tile/include/asm/sigcontext.h index 5e2d03336f53..6348e59d3724 100644 --- a/arch/tile/include/asm/sigcontext.h +++ b/arch/tile/include/asm/sigcontext.h @@ -15,6 +15,8 @@ #ifndef _ASM_TILE_SIGCONTEXT_H #define _ASM_TILE_SIGCONTEXT_H +/* Don't pollute the namespace since includes this file. */ +#define __need_int_reg_t #include /* @@ -22,14 +24,14 @@ * but is simplified since we know the fault is from userspace. */ struct sigcontext { - uint_reg_t gregs[53]; /* General-purpose registers. */ - uint_reg_t tp; /* Aliases gregs[TREG_TP]. */ - uint_reg_t sp; /* Aliases gregs[TREG_SP]. */ - uint_reg_t lr; /* Aliases gregs[TREG_LR]. */ - uint_reg_t pc; /* Program counter. */ - uint_reg_t ics; /* In Interrupt Critical Section? */ - uint_reg_t faultnum; /* Fault number. */ - uint_reg_t pad[5]; + __uint_reg_t gregs[53]; /* General-purpose registers. */ + __uint_reg_t tp; /* Aliases gregs[TREG_TP]. */ + __uint_reg_t sp; /* Aliases gregs[TREG_SP]. */ + __uint_reg_t lr; /* Aliases gregs[TREG_LR]. */ + __uint_reg_t pc; /* Program counter. */ + __uint_reg_t ics; /* In Interrupt Critical Section? */ + __uint_reg_t faultnum; /* Fault number. */ + __uint_reg_t pad[5]; }; #endif /* _ASM_TILE_SIGCONTEXT_H */ From f319d6e238a25d84af530a6a2526525c7041463f Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 2 Nov 2011 22:23:41 -0400 Subject: [PATCH 1383/1596] arch/tile: avoid exporting a symbol no longer used by gcc An earlier Tilera compiler generated calls to an "__ll_mul" function for long long multiplication. Our libgcc supported that as an alias for the normal __muldi3 routine, so we made it available to kernel modules as well. However, for a while now the compiler has internally been generating only the standard __muldi3 symbol, and the version we are giving back to the community does not have the __ll_mul alias, so we are removing it from the kernel too. Signed-off-by: Chris Metcalf --- arch/tile/lib/exports.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c index 49284fae9d09..a87d2a859ba9 100644 --- a/arch/tile/lib/exports.c +++ b/arch/tile/lib/exports.c @@ -79,8 +79,6 @@ EXPORT_SYMBOL(__umoddi3); int64_t __moddi3(int64_t dividend, int64_t divisor); EXPORT_SYMBOL(__moddi3); #ifndef __tilegx__ -uint64_t __ll_mul(uint64_t n0, uint64_t n1); -EXPORT_SYMBOL(__ll_mul); int64_t __muldi3(int64_t, int64_t); EXPORT_SYMBOL(__muldi3); uint64_t __lshrdi3(uint64_t, unsigned int); From aeddea5d37d86d38c7a347110d8a052e9f45d955 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 2 Nov 2011 22:33:07 -0400 Subject: [PATCH 1384/1596] arch/tile: add the headers to the set of installed kernel headers These headers are similar to the headers that describe kernel APIs, but instead describe aspects of the actual hardware in an OS- and application-independent manner. We need to include them in the set of installed headers so that userspace tools (including glibc) can build purely from the provided kernel headers. Signed-off-by: Chris Metcalf --- arch/tile/include/arch/Kbuild | 17 +++++++++++++++++ arch/tile/include/asm/Kbuild | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 arch/tile/include/arch/Kbuild diff --git a/arch/tile/include/arch/Kbuild b/arch/tile/include/arch/Kbuild new file mode 100644 index 000000000000..9c0ea24cc948 --- /dev/null +++ b/arch/tile/include/arch/Kbuild @@ -0,0 +1,17 @@ +header-y += abi.h +header-y += chip.h +header-y += chip_tile64.h +header-y += chip_tilegx.h +header-y += chip_tilepro.h +header-y += icache.h +header-y += interrupts.h +header-y += interrupts_32.h +header-y += interrupts_64.h +header-y += opcode.h +header-y += opcode_tilegx.h +header-y += opcode_tilepro.h +header-y += sim.h +header-y += sim_def.h +header-y += spr_def.h +header-y += spr_def_32.h +header-y += spr_def_64.h diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild index aec60dc06007..0bb42642343a 100644 --- a/arch/tile/include/asm/Kbuild +++ b/arch/tile/include/asm/Kbuild @@ -1,5 +1,7 @@ include include/asm-generic/Kbuild.asm +header-y += ../arch/ + header-y += ucontext.h header-y += hardwall.h From eb7c792da5afa3b9ec3e802c30952f82d2e9722b Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 2 Nov 2011 23:02:17 -0400 Subject: [PATCH 1385/1596] arch/tile: factor out header The kernel code was using some headers that included a mix of hardware-specific information (typically found in Tilera headers) and structures, enums, and function declarations supporting the disassembly function of the tile-desc.c sources. This change refactors that code so that a hardware-specific, but OS- and application-agnostic header, is created: . This header is then exported to userspace along with the other headers and can be used to build userspace code; in particular, it is used by glibc as part of implementing the backtrace() function. The new header, together with a header that specifically describes the disassembly code ( with _32 and _64 variants), replaces the old and headers. As part of this change, we are also renaming the 32-bit constants from TILE_xxx to TILEPRO_xxx to better reflect the fact that they are specific to the TILEPro architecture, and not to TILE-Gx and any successor "tile" architecture chips. Signed-off-by: Chris Metcalf --- .../{asm/opcode_constants.h => arch/opcode.h} | 17 +- .../opcode_tilegx.h} | 806 +++++- arch/tile/include/arch/opcode_tilepro.h | 1471 +++++++++++ arch/tile/include/asm/opcode-tile_32.h | 1513 ----------- arch/tile/include/asm/opcode-tile_64.h | 1248 --------- arch/tile/include/asm/opcode_constants_32.h | 480 ---- .../asm/{opcode-tile.h => tile-desc.h} | 19 +- arch/tile/include/asm/tile-desc_32.h | 553 ++++ arch/tile/include/asm/tile-desc_64.h | 483 ++++ arch/tile/kernel/backtrace.c | 19 +- arch/tile/kernel/module.c | 2 +- arch/tile/kernel/single_step.c | 9 +- arch/tile/kernel/tile-desc_32.c | 2242 +++++++++-------- arch/tile/kernel/tile-desc_64.c | 28 +- arch/tile/kernel/traps.c | 5 +- 15 files changed, 4536 insertions(+), 4359 deletions(-) rename arch/tile/include/{asm/opcode_constants.h => arch/opcode.h} (62%) rename arch/tile/include/{asm/opcode_constants_64.h => arch/opcode_tilegx.h} (50%) create mode 100644 arch/tile/include/arch/opcode_tilepro.h delete mode 100644 arch/tile/include/asm/opcode-tile_32.h delete mode 100644 arch/tile/include/asm/opcode-tile_64.h delete mode 100644 arch/tile/include/asm/opcode_constants_32.h rename arch/tile/include/asm/{opcode-tile.h => tile-desc.h} (56%) create mode 100644 arch/tile/include/asm/tile-desc_32.h create mode 100644 arch/tile/include/asm/tile-desc_64.h diff --git a/arch/tile/include/asm/opcode_constants.h b/arch/tile/include/arch/opcode.h similarity index 62% rename from arch/tile/include/asm/opcode_constants.h rename to arch/tile/include/arch/opcode.h index 37a9f2958cb1..92d15229ecec 100644 --- a/arch/tile/include/asm/opcode_constants.h +++ b/arch/tile/include/arch/opcode.h @@ -1,5 +1,5 @@ /* - * Copyright 2010 Tilera Corporation. All Rights Reserved. + * Copyright 2011 Tilera Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,15 +12,10 @@ * more details. */ -#ifndef _ASM_TILE_OPCODE_CONSTANTS_H -#define _ASM_TILE_OPCODE_CONSTANTS_H - -#include - -#if CHIP_WORD_SIZE() == 64 -#include +#if defined(__tilepro__) +#include +#elif defined(__tilegx__) +#include #else -#include +#error Unexpected Tilera chip type #endif - -#endif /* _ASM_TILE_OPCODE_CONSTANTS_H */ diff --git a/arch/tile/include/asm/opcode_constants_64.h b/arch/tile/include/arch/opcode_tilegx.h similarity index 50% rename from arch/tile/include/asm/opcode_constants_64.h rename to arch/tile/include/arch/opcode_tilegx.h index 710192869476..c14d02c81600 100644 --- a/arch/tile/include/asm/opcode_constants_64.h +++ b/arch/tile/include/arch/opcode_tilegx.h @@ -1,4 +1,5 @@ -/* +/* TILE-Gx opcode information. + * * Copyright 2011 Tilera Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -10,13 +11,805 @@ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for * more details. + * + * + * + * + * */ -/* This file is machine-generated; DO NOT EDIT! */ +#ifndef __ARCH_OPCODE_H__ +#define __ARCH_OPCODE_H__ + +#ifndef __ASSEMBLER__ + +typedef unsigned long long tilegx_bundle_bits; + +/* These are the bits that determine if a bundle is in the X encoding. */ +#define TILEGX_BUNDLE_MODE_MASK ((tilegx_bundle_bits)3 << 62) + +enum +{ + /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */ + TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE = 3, + + /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */ + TILEGX_NUM_PIPELINE_ENCODINGS = 5, + + /* Log base 2 of TILEGX_BUNDLE_SIZE_IN_BYTES. */ + TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES = 3, + + /* Instructions take this many bytes. */ + TILEGX_BUNDLE_SIZE_IN_BYTES = 1 << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES, + + /* Log base 2 of TILEGX_BUNDLE_ALIGNMENT_IN_BYTES. */ + TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3, + + /* Bundles should be aligned modulo this number of bytes. */ + TILEGX_BUNDLE_ALIGNMENT_IN_BYTES = + (1 << TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES), + + /* Number of registers (some are magic, such as network I/O). */ + TILEGX_NUM_REGISTERS = 64, +}; + +/* Make a few "tile_" variables to simplify common code between + architectures. */ + +typedef tilegx_bundle_bits tile_bundle_bits; +#define TILE_BUNDLE_SIZE_IN_BYTES TILEGX_BUNDLE_SIZE_IN_BYTES +#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES +#define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ + TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES + +/* 64-bit pattern for a { bpt ; nop } bundle. */ +#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL + +static __inline unsigned int +get_BFEnd_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_BFOpcodeExtension_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 24)) & 0xf); +} + +static __inline unsigned int +get_BFStart_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 18)) & 0x3f); +} + +static __inline unsigned int +get_BrOff_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x0000003f) | + (((unsigned int)(n >> 37)) & 0x0001ffc0); +} + +static __inline unsigned int +get_BrType_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 54)) & 0x1f); +} + +static __inline unsigned int +get_Dest_Imm8_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x0000003f) | + (((unsigned int)(n >> 43)) & 0x000000c0); +} + +static __inline unsigned int +get_Dest_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0x3f); +} + +static __inline unsigned int +get_Dest_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x3f); +} + +static __inline unsigned int +get_Dest_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0x3f); +} + +static __inline unsigned int +get_Dest_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x3f); +} + +static __inline unsigned int +get_Imm16_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0xffff); +} + +static __inline unsigned int +get_Imm16_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0xffff); +} + +static __inline unsigned int +get_Imm8OpcodeExtension_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 20)) & 0xff); +} + +static __inline unsigned int +get_Imm8OpcodeExtension_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 51)) & 0xff); +} + +static __inline unsigned int +get_Imm8_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0xff); +} + +static __inline unsigned int +get_Imm8_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0xff); +} + +static __inline unsigned int +get_Imm8_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0xff); +} + +static __inline unsigned int +get_Imm8_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0xff); +} + +static __inline unsigned int +get_JumpOff_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x7ffffff); +} + +static __inline unsigned int +get_JumpOpcodeExtension_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 58)) & 0x1); +} + +static __inline unsigned int +get_MF_Imm14_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 37)) & 0x3fff); +} + +static __inline unsigned int +get_MT_Imm14_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x0000003f) | + (((unsigned int)(n >> 37)) & 0x00003fc0); +} + +static __inline unsigned int +get_Mode(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 62)) & 0x3); +} + +static __inline unsigned int +get_Opcode_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 28)) & 0x7); +} + +static __inline unsigned int +get_Opcode_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 59)) & 0x7); +} + +static __inline unsigned int +get_Opcode_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 27)) & 0xf); +} + +static __inline unsigned int +get_Opcode_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 58)) & 0xf); +} + +static __inline unsigned int +get_Opcode_Y2(tilegx_bundle_bits n) +{ + return (((n >> 26)) & 0x00000001) | + (((unsigned int)(n >> 56)) & 0x00000002); +} + +static __inline unsigned int +get_RRROpcodeExtension_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 18)) & 0x3ff); +} + +static __inline unsigned int +get_RRROpcodeExtension_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 49)) & 0x3ff); +} + +static __inline unsigned int +get_RRROpcodeExtension_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 18)) & 0x3); +} + +static __inline unsigned int +get_RRROpcodeExtension_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 49)) & 0x3); +} + +static __inline unsigned int +get_ShAmt_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_ShAmt_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x3f); +} + +static __inline unsigned int +get_ShAmt_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_ShAmt_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x3f); +} + +static __inline unsigned int +get_ShiftOpcodeExtension_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 18)) & 0x3ff); +} + +static __inline unsigned int +get_ShiftOpcodeExtension_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 49)) & 0x3ff); +} + +static __inline unsigned int +get_ShiftOpcodeExtension_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 18)) & 0x3); +} + +static __inline unsigned int +get_ShiftOpcodeExtension_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 49)) & 0x3); +} + +static __inline unsigned int +get_SrcA_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 6)) & 0x3f); +} + +static __inline unsigned int +get_SrcA_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 37)) & 0x3f); +} + +static __inline unsigned int +get_SrcA_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 6)) & 0x3f); +} + +static __inline unsigned int +get_SrcA_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 37)) & 0x3f); +} + +static __inline unsigned int +get_SrcA_Y2(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 20)) & 0x3f); +} + +static __inline unsigned int +get_SrcBDest_Y2(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 51)) & 0x3f); +} + +static __inline unsigned int +get_SrcB_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_SrcB_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x3f); +} + +static __inline unsigned int +get_SrcB_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_SrcB_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x3f); +} + +static __inline unsigned int +get_UnaryOpcodeExtension_X0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_UnaryOpcodeExtension_X1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x3f); +} + +static __inline unsigned int +get_UnaryOpcodeExtension_Y0(tilegx_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_UnaryOpcodeExtension_Y1(tilegx_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x3f); +} + + +static __inline int +sign_extend(int n, int num_bits) +{ + int shift = (int)(sizeof(int) * 8 - num_bits); + return (n << shift) >> shift; +} + + + +static __inline tilegx_bundle_bits +create_BFEnd_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilegx_bundle_bits +create_BFOpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xf) << 24); +} + +static __inline tilegx_bundle_bits +create_BFStart_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 18); +} + +static __inline tilegx_bundle_bits +create_BrOff_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | + (((tilegx_bundle_bits)(n & 0x0001ffc0)) << 37); +} + +static __inline tilegx_bundle_bits +create_BrType_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x1f)) << 54); +} + +static __inline tilegx_bundle_bits +create_Dest_Imm8_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | + (((tilegx_bundle_bits)(n & 0x000000c0)) << 43); +} + +static __inline tilegx_bundle_bits +create_Dest_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 0); +} + +static __inline tilegx_bundle_bits +create_Dest_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 31); +} + +static __inline tilegx_bundle_bits +create_Dest_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 0); +} + +static __inline tilegx_bundle_bits +create_Dest_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 31); +} + +static __inline tilegx_bundle_bits +create_Imm16_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xffff) << 12); +} + +static __inline tilegx_bundle_bits +create_Imm16_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0xffff)) << 43); +} + +static __inline tilegx_bundle_bits +create_Imm8OpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xff) << 20); +} + +static __inline tilegx_bundle_bits +create_Imm8OpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0xff)) << 51); +} + +static __inline tilegx_bundle_bits +create_Imm8_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xff) << 12); +} + +static __inline tilegx_bundle_bits +create_Imm8_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0xff)) << 43); +} + +static __inline tilegx_bundle_bits +create_Imm8_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xff) << 12); +} + +static __inline tilegx_bundle_bits +create_Imm8_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0xff)) << 43); +} + +static __inline tilegx_bundle_bits +create_JumpOff_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x7ffffff)) << 31); +} + +static __inline tilegx_bundle_bits +create_JumpOpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x1)) << 58); +} + +static __inline tilegx_bundle_bits +create_MF_Imm14_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3fff)) << 37); +} + +static __inline tilegx_bundle_bits +create_MT_Imm14_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | + (((tilegx_bundle_bits)(n & 0x00003fc0)) << 37); +} + +static __inline tilegx_bundle_bits +create_Mode(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3)) << 62); +} + +static __inline tilegx_bundle_bits +create_Opcode_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x7) << 28); +} + +static __inline tilegx_bundle_bits +create_Opcode_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x7)) << 59); +} + +static __inline tilegx_bundle_bits +create_Opcode_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xf) << 27); +} + +static __inline tilegx_bundle_bits +create_Opcode_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0xf)) << 58); +} + +static __inline tilegx_bundle_bits +create_Opcode_Y2(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x00000001) << 26) | + (((tilegx_bundle_bits)(n & 0x00000002)) << 56); +} + +static __inline tilegx_bundle_bits +create_RRROpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3ff) << 18); +} + +static __inline tilegx_bundle_bits +create_RRROpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3ff)) << 49); +} + +static __inline tilegx_bundle_bits +create_RRROpcodeExtension_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3) << 18); +} + +static __inline tilegx_bundle_bits +create_RRROpcodeExtension_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3)) << 49); +} + +static __inline tilegx_bundle_bits +create_ShAmt_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilegx_bundle_bits +create_ShAmt_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 43); +} + +static __inline tilegx_bundle_bits +create_ShAmt_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilegx_bundle_bits +create_ShAmt_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 43); +} + +static __inline tilegx_bundle_bits +create_ShiftOpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3ff) << 18); +} + +static __inline tilegx_bundle_bits +create_ShiftOpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3ff)) << 49); +} + +static __inline tilegx_bundle_bits +create_ShiftOpcodeExtension_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3) << 18); +} + +static __inline tilegx_bundle_bits +create_ShiftOpcodeExtension_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3)) << 49); +} + +static __inline tilegx_bundle_bits +create_SrcA_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 6); +} + +static __inline tilegx_bundle_bits +create_SrcA_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 37); +} + +static __inline tilegx_bundle_bits +create_SrcA_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 6); +} + +static __inline tilegx_bundle_bits +create_SrcA_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 37); +} + +static __inline tilegx_bundle_bits +create_SrcA_Y2(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 20); +} + +static __inline tilegx_bundle_bits +create_SrcBDest_Y2(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 51); +} + +static __inline tilegx_bundle_bits +create_SrcB_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilegx_bundle_bits +create_SrcB_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 43); +} + +static __inline tilegx_bundle_bits +create_SrcB_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilegx_bundle_bits +create_SrcB_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 43); +} + +static __inline tilegx_bundle_bits +create_UnaryOpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilegx_bundle_bits +create_UnaryOpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 43); +} + +static __inline tilegx_bundle_bits +create_UnaryOpcodeExtension_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilegx_bundle_bits +create_UnaryOpcodeExtension_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilegx_bundle_bits)(n & 0x3f)) << 43); +} -#ifndef _TILE_OPCODE_CONSTANTS_H -#define _TILE_OPCODE_CONSTANTS_H enum { ADDI_IMM8_OPCODE_X0 = 1, @@ -606,4 +1399,7 @@ enum XOR_RRR_5_OPCODE_Y1 = 3 }; -#endif /* !_TILE_OPCODE_CONSTANTS_H */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __ARCH_OPCODE_H__ */ diff --git a/arch/tile/include/arch/opcode_tilepro.h b/arch/tile/include/arch/opcode_tilepro.h new file mode 100644 index 000000000000..71b763b8ce83 --- /dev/null +++ b/arch/tile/include/arch/opcode_tilepro.h @@ -0,0 +1,1471 @@ +/* TILEPro opcode information. + * + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * + * + * + * + */ + +#ifndef __ARCH_OPCODE_H__ +#define __ARCH_OPCODE_H__ + +#ifndef __ASSEMBLER__ + +typedef unsigned long long tilepro_bundle_bits; + +/* This is the bit that determines if a bundle is in the Y encoding. */ +#define TILEPRO_BUNDLE_Y_ENCODING_MASK ((tilepro_bundle_bits)1 << 63) + +enum +{ + /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */ + TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE = 3, + + /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */ + TILEPRO_NUM_PIPELINE_ENCODINGS = 5, + + /* Log base 2 of TILEPRO_BUNDLE_SIZE_IN_BYTES. */ + TILEPRO_LOG2_BUNDLE_SIZE_IN_BYTES = 3, + + /* Instructions take this many bytes. */ + TILEPRO_BUNDLE_SIZE_IN_BYTES = 1 << TILEPRO_LOG2_BUNDLE_SIZE_IN_BYTES, + + /* Log base 2 of TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES. */ + TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3, + + /* Bundles should be aligned modulo this number of bytes. */ + TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES = + (1 << TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES), + + /* Log base 2 of TILEPRO_SN_INSTRUCTION_SIZE_IN_BYTES. */ + TILEPRO_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES = 1, + + /* Static network instructions take this many bytes. */ + TILEPRO_SN_INSTRUCTION_SIZE_IN_BYTES = + (1 << TILEPRO_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES), + + /* Number of registers (some are magic, such as network I/O). */ + TILEPRO_NUM_REGISTERS = 64, + + /* Number of static network registers. */ + TILEPRO_NUM_SN_REGISTERS = 4 +}; + +/* Make a few "tile_" variables to simplify common code between + architectures. */ + +typedef tilepro_bundle_bits tile_bundle_bits; +#define TILE_BUNDLE_SIZE_IN_BYTES TILEPRO_BUNDLE_SIZE_IN_BYTES +#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES +#define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ + TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES + +/* 64-bit pattern for a { bpt ; nop } bundle. */ +#define TILEPRO_BPT_BUNDLE 0x400b3cae70166000ULL + +static __inline unsigned int +get_BrOff_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0x3ff); +} + +static __inline unsigned int +get_BrOff_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x00007fff) | + (((unsigned int)(n >> 20)) & 0x00018000); +} + +static __inline unsigned int +get_BrType_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0xf); +} + +static __inline unsigned int +get_Dest_Imm8_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x0000003f) | + (((unsigned int)(n >> 43)) & 0x000000c0); +} + +static __inline unsigned int +get_Dest_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 2)) & 0x3); +} + +static __inline unsigned int +get_Dest_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0x3f); +} + +static __inline unsigned int +get_Dest_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x3f); +} + +static __inline unsigned int +get_Dest_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0x3f); +} + +static __inline unsigned int +get_Dest_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x3f); +} + +static __inline unsigned int +get_Imm16_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0xffff); +} + +static __inline unsigned int +get_Imm16_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0xffff); +} + +static __inline unsigned int +get_Imm8_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0xff); +} + +static __inline unsigned int +get_Imm8_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0xff); +} + +static __inline unsigned int +get_Imm8_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0xff); +} + +static __inline unsigned int +get_Imm8_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0xff); +} + +static __inline unsigned int +get_Imm8_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0xff); +} + +static __inline unsigned int +get_ImmOpcodeExtension_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 20)) & 0x7f); +} + +static __inline unsigned int +get_ImmOpcodeExtension_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 51)) & 0x7f); +} + +static __inline unsigned int +get_ImmRROpcodeExtension_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 8)) & 0x3); +} + +static __inline unsigned int +get_JOffLong_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x00007fff) | + (((unsigned int)(n >> 20)) & 0x00018000) | + (((unsigned int)(n >> 14)) & 0x001e0000) | + (((unsigned int)(n >> 16)) & 0x07e00000) | + (((unsigned int)(n >> 31)) & 0x18000000); +} + +static __inline unsigned int +get_JOff_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x00007fff) | + (((unsigned int)(n >> 20)) & 0x00018000) | + (((unsigned int)(n >> 14)) & 0x001e0000) | + (((unsigned int)(n >> 16)) & 0x07e00000) | + (((unsigned int)(n >> 31)) & 0x08000000); +} + +static __inline unsigned int +get_MF_Imm15_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 37)) & 0x00003fff) | + (((unsigned int)(n >> 44)) & 0x00004000); +} + +static __inline unsigned int +get_MMEnd_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 18)) & 0x1f); +} + +static __inline unsigned int +get_MMEnd_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 49)) & 0x1f); +} + +static __inline unsigned int +get_MMStart_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 23)) & 0x1f); +} + +static __inline unsigned int +get_MMStart_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 54)) & 0x1f); +} + +static __inline unsigned int +get_MT_Imm15_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 31)) & 0x0000003f) | + (((unsigned int)(n >> 37)) & 0x00003fc0) | + (((unsigned int)(n >> 44)) & 0x00004000); +} + +static __inline unsigned int +get_Mode(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 63)) & 0x1); +} + +static __inline unsigned int +get_NoRegOpcodeExtension_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0xf); +} + +static __inline unsigned int +get_Opcode_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 10)) & 0x3f); +} + +static __inline unsigned int +get_Opcode_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 28)) & 0x7); +} + +static __inline unsigned int +get_Opcode_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 59)) & 0xf); +} + +static __inline unsigned int +get_Opcode_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 27)) & 0xf); +} + +static __inline unsigned int +get_Opcode_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 59)) & 0xf); +} + +static __inline unsigned int +get_Opcode_Y2(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 56)) & 0x7); +} + +static __inline unsigned int +get_RROpcodeExtension_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 4)) & 0xf); +} + +static __inline unsigned int +get_RRROpcodeExtension_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 18)) & 0x1ff); +} + +static __inline unsigned int +get_RRROpcodeExtension_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 49)) & 0x1ff); +} + +static __inline unsigned int +get_RRROpcodeExtension_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 18)) & 0x3); +} + +static __inline unsigned int +get_RRROpcodeExtension_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 49)) & 0x3); +} + +static __inline unsigned int +get_RouteOpcodeExtension_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0x3ff); +} + +static __inline unsigned int +get_S_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 27)) & 0x1); +} + +static __inline unsigned int +get_S_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 58)) & 0x1); +} + +static __inline unsigned int +get_ShAmt_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x1f); +} + +static __inline unsigned int +get_ShAmt_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x1f); +} + +static __inline unsigned int +get_ShAmt_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x1f); +} + +static __inline unsigned int +get_ShAmt_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x1f); +} + +static __inline unsigned int +get_SrcA_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 6)) & 0x3f); +} + +static __inline unsigned int +get_SrcA_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 37)) & 0x3f); +} + +static __inline unsigned int +get_SrcA_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 6)) & 0x3f); +} + +static __inline unsigned int +get_SrcA_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 37)) & 0x3f); +} + +static __inline unsigned int +get_SrcA_Y2(tilepro_bundle_bits n) +{ + return (((n >> 26)) & 0x00000001) | + (((unsigned int)(n >> 50)) & 0x0000003e); +} + +static __inline unsigned int +get_SrcBDest_Y2(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 20)) & 0x3f); +} + +static __inline unsigned int +get_SrcB_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_SrcB_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x3f); +} + +static __inline unsigned int +get_SrcB_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x3f); +} + +static __inline unsigned int +get_SrcB_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x3f); +} + +static __inline unsigned int +get_Src_SN(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 0)) & 0x3); +} + +static __inline unsigned int +get_UnOpcodeExtension_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x1f); +} + +static __inline unsigned int +get_UnOpcodeExtension_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x1f); +} + +static __inline unsigned int +get_UnOpcodeExtension_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 12)) & 0x1f); +} + +static __inline unsigned int +get_UnOpcodeExtension_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 43)) & 0x1f); +} + +static __inline unsigned int +get_UnShOpcodeExtension_X0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 17)) & 0x3ff); +} + +static __inline unsigned int +get_UnShOpcodeExtension_X1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 48)) & 0x3ff); +} + +static __inline unsigned int +get_UnShOpcodeExtension_Y0(tilepro_bundle_bits num) +{ + const unsigned int n = (unsigned int)num; + return (((n >> 17)) & 0x7); +} + +static __inline unsigned int +get_UnShOpcodeExtension_Y1(tilepro_bundle_bits n) +{ + return (((unsigned int)(n >> 48)) & 0x7); +} + + +static __inline int +sign_extend(int n, int num_bits) +{ + int shift = (int)(sizeof(int) * 8 - num_bits); + return (n << shift) >> shift; +} + + + +static __inline tilepro_bundle_bits +create_BrOff_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3ff) << 0); +} + +static __inline tilepro_bundle_bits +create_BrOff_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x00007fff)) << 43) | + (((tilepro_bundle_bits)(n & 0x00018000)) << 20); +} + +static __inline tilepro_bundle_bits +create_BrType_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0xf)) << 31); +} + +static __inline tilepro_bundle_bits +create_Dest_Imm8_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x0000003f)) << 31) | + (((tilepro_bundle_bits)(n & 0x000000c0)) << 43); +} + +static __inline tilepro_bundle_bits +create_Dest_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3) << 2); +} + +static __inline tilepro_bundle_bits +create_Dest_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 0); +} + +static __inline tilepro_bundle_bits +create_Dest_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x3f)) << 31); +} + +static __inline tilepro_bundle_bits +create_Dest_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 0); +} + +static __inline tilepro_bundle_bits +create_Dest_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x3f)) << 31); +} + +static __inline tilepro_bundle_bits +create_Imm16_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xffff) << 12); +} + +static __inline tilepro_bundle_bits +create_Imm16_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0xffff)) << 43); +} + +static __inline tilepro_bundle_bits +create_Imm8_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xff) << 0); +} + +static __inline tilepro_bundle_bits +create_Imm8_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xff) << 12); +} + +static __inline tilepro_bundle_bits +create_Imm8_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0xff)) << 43); +} + +static __inline tilepro_bundle_bits +create_Imm8_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xff) << 12); +} + +static __inline tilepro_bundle_bits +create_Imm8_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0xff)) << 43); +} + +static __inline tilepro_bundle_bits +create_ImmOpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x7f) << 20); +} + +static __inline tilepro_bundle_bits +create_ImmOpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x7f)) << 51); +} + +static __inline tilepro_bundle_bits +create_ImmRROpcodeExtension_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3) << 8); +} + +static __inline tilepro_bundle_bits +create_JOffLong_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x00007fff)) << 43) | + (((tilepro_bundle_bits)(n & 0x00018000)) << 20) | + (((tilepro_bundle_bits)(n & 0x001e0000)) << 14) | + (((tilepro_bundle_bits)(n & 0x07e00000)) << 16) | + (((tilepro_bundle_bits)(n & 0x18000000)) << 31); +} + +static __inline tilepro_bundle_bits +create_JOff_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x00007fff)) << 43) | + (((tilepro_bundle_bits)(n & 0x00018000)) << 20) | + (((tilepro_bundle_bits)(n & 0x001e0000)) << 14) | + (((tilepro_bundle_bits)(n & 0x07e00000)) << 16) | + (((tilepro_bundle_bits)(n & 0x08000000)) << 31); +} + +static __inline tilepro_bundle_bits +create_MF_Imm15_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x00003fff)) << 37) | + (((tilepro_bundle_bits)(n & 0x00004000)) << 44); +} + +static __inline tilepro_bundle_bits +create_MMEnd_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x1f) << 18); +} + +static __inline tilepro_bundle_bits +create_MMEnd_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1f)) << 49); +} + +static __inline tilepro_bundle_bits +create_MMStart_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x1f) << 23); +} + +static __inline tilepro_bundle_bits +create_MMStart_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1f)) << 54); +} + +static __inline tilepro_bundle_bits +create_MT_Imm15_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x0000003f)) << 31) | + (((tilepro_bundle_bits)(n & 0x00003fc0)) << 37) | + (((tilepro_bundle_bits)(n & 0x00004000)) << 44); +} + +static __inline tilepro_bundle_bits +create_Mode(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1)) << 63); +} + +static __inline tilepro_bundle_bits +create_NoRegOpcodeExtension_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xf) << 0); +} + +static __inline tilepro_bundle_bits +create_Opcode_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 10); +} + +static __inline tilepro_bundle_bits +create_Opcode_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x7) << 28); +} + +static __inline tilepro_bundle_bits +create_Opcode_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0xf)) << 59); +} + +static __inline tilepro_bundle_bits +create_Opcode_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xf) << 27); +} + +static __inline tilepro_bundle_bits +create_Opcode_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0xf)) << 59); +} + +static __inline tilepro_bundle_bits +create_Opcode_Y2(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x7)) << 56); +} + +static __inline tilepro_bundle_bits +create_RROpcodeExtension_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0xf) << 4); +} + +static __inline tilepro_bundle_bits +create_RRROpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x1ff) << 18); +} + +static __inline tilepro_bundle_bits +create_RRROpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1ff)) << 49); +} + +static __inline tilepro_bundle_bits +create_RRROpcodeExtension_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3) << 18); +} + +static __inline tilepro_bundle_bits +create_RRROpcodeExtension_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x3)) << 49); +} + +static __inline tilepro_bundle_bits +create_RouteOpcodeExtension_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3ff) << 0); +} + +static __inline tilepro_bundle_bits +create_S_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x1) << 27); +} + +static __inline tilepro_bundle_bits +create_S_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1)) << 58); +} + +static __inline tilepro_bundle_bits +create_ShAmt_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x1f) << 12); +} + +static __inline tilepro_bundle_bits +create_ShAmt_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1f)) << 43); +} + +static __inline tilepro_bundle_bits +create_ShAmt_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x1f) << 12); +} + +static __inline tilepro_bundle_bits +create_ShAmt_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1f)) << 43); +} + +static __inline tilepro_bundle_bits +create_SrcA_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 6); +} + +static __inline tilepro_bundle_bits +create_SrcA_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x3f)) << 37); +} + +static __inline tilepro_bundle_bits +create_SrcA_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 6); +} + +static __inline tilepro_bundle_bits +create_SrcA_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x3f)) << 37); +} + +static __inline tilepro_bundle_bits +create_SrcA_Y2(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x00000001) << 26) | + (((tilepro_bundle_bits)(n & 0x0000003e)) << 50); +} + +static __inline tilepro_bundle_bits +create_SrcBDest_Y2(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 20); +} + +static __inline tilepro_bundle_bits +create_SrcB_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilepro_bundle_bits +create_SrcB_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x3f)) << 43); +} + +static __inline tilepro_bundle_bits +create_SrcB_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3f) << 12); +} + +static __inline tilepro_bundle_bits +create_SrcB_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x3f)) << 43); +} + +static __inline tilepro_bundle_bits +create_Src_SN(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3) << 0); +} + +static __inline tilepro_bundle_bits +create_UnOpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x1f) << 12); +} + +static __inline tilepro_bundle_bits +create_UnOpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1f)) << 43); +} + +static __inline tilepro_bundle_bits +create_UnOpcodeExtension_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x1f) << 12); +} + +static __inline tilepro_bundle_bits +create_UnOpcodeExtension_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x1f)) << 43); +} + +static __inline tilepro_bundle_bits +create_UnShOpcodeExtension_X0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x3ff) << 17); +} + +static __inline tilepro_bundle_bits +create_UnShOpcodeExtension_X1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x3ff)) << 48); +} + +static __inline tilepro_bundle_bits +create_UnShOpcodeExtension_Y0(int num) +{ + const unsigned int n = (unsigned int)num; + return ((n & 0x7) << 17); +} + +static __inline tilepro_bundle_bits +create_UnShOpcodeExtension_Y1(int num) +{ + const unsigned int n = (unsigned int)num; + return (((tilepro_bundle_bits)(n & 0x7)) << 48); +} + + +enum +{ + ADDBS_U_SPECIAL_0_OPCODE_X0 = 98, + ADDBS_U_SPECIAL_0_OPCODE_X1 = 68, + ADDB_SPECIAL_0_OPCODE_X0 = 1, + ADDB_SPECIAL_0_OPCODE_X1 = 1, + ADDHS_SPECIAL_0_OPCODE_X0 = 99, + ADDHS_SPECIAL_0_OPCODE_X1 = 69, + ADDH_SPECIAL_0_OPCODE_X0 = 2, + ADDH_SPECIAL_0_OPCODE_X1 = 2, + ADDIB_IMM_0_OPCODE_X0 = 1, + ADDIB_IMM_0_OPCODE_X1 = 1, + ADDIH_IMM_0_OPCODE_X0 = 2, + ADDIH_IMM_0_OPCODE_X1 = 2, + ADDI_IMM_0_OPCODE_X0 = 3, + ADDI_IMM_0_OPCODE_X1 = 3, + ADDI_IMM_1_OPCODE_SN = 1, + ADDI_OPCODE_Y0 = 9, + ADDI_OPCODE_Y1 = 7, + ADDLIS_OPCODE_X0 = 1, + ADDLIS_OPCODE_X1 = 2, + ADDLI_OPCODE_X0 = 2, + ADDLI_OPCODE_X1 = 3, + ADDS_SPECIAL_0_OPCODE_X0 = 96, + ADDS_SPECIAL_0_OPCODE_X1 = 66, + ADD_SPECIAL_0_OPCODE_X0 = 3, + ADD_SPECIAL_0_OPCODE_X1 = 3, + ADD_SPECIAL_0_OPCODE_Y0 = 0, + ADD_SPECIAL_0_OPCODE_Y1 = 0, + ADIFFB_U_SPECIAL_0_OPCODE_X0 = 4, + ADIFFH_SPECIAL_0_OPCODE_X0 = 5, + ANDI_IMM_0_OPCODE_X0 = 1, + ANDI_IMM_0_OPCODE_X1 = 4, + ANDI_OPCODE_Y0 = 10, + ANDI_OPCODE_Y1 = 8, + AND_SPECIAL_0_OPCODE_X0 = 6, + AND_SPECIAL_0_OPCODE_X1 = 4, + AND_SPECIAL_2_OPCODE_Y0 = 0, + AND_SPECIAL_2_OPCODE_Y1 = 0, + AULI_OPCODE_X0 = 3, + AULI_OPCODE_X1 = 4, + AVGB_U_SPECIAL_0_OPCODE_X0 = 7, + AVGH_SPECIAL_0_OPCODE_X0 = 8, + BBNST_BRANCH_OPCODE_X1 = 15, + BBNS_BRANCH_OPCODE_X1 = 14, + BBNS_OPCODE_SN = 63, + BBST_BRANCH_OPCODE_X1 = 13, + BBS_BRANCH_OPCODE_X1 = 12, + BBS_OPCODE_SN = 62, + BGEZT_BRANCH_OPCODE_X1 = 7, + BGEZ_BRANCH_OPCODE_X1 = 6, + BGEZ_OPCODE_SN = 61, + BGZT_BRANCH_OPCODE_X1 = 5, + BGZ_BRANCH_OPCODE_X1 = 4, + BGZ_OPCODE_SN = 58, + BITX_UN_0_SHUN_0_OPCODE_X0 = 1, + BITX_UN_0_SHUN_0_OPCODE_Y0 = 1, + BLEZT_BRANCH_OPCODE_X1 = 11, + BLEZ_BRANCH_OPCODE_X1 = 10, + BLEZ_OPCODE_SN = 59, + BLZT_BRANCH_OPCODE_X1 = 9, + BLZ_BRANCH_OPCODE_X1 = 8, + BLZ_OPCODE_SN = 60, + BNZT_BRANCH_OPCODE_X1 = 3, + BNZ_BRANCH_OPCODE_X1 = 2, + BNZ_OPCODE_SN = 57, + BPT_NOREG_RR_IMM_0_OPCODE_SN = 1, + BRANCH_OPCODE_X1 = 5, + BYTEX_UN_0_SHUN_0_OPCODE_X0 = 2, + BYTEX_UN_0_SHUN_0_OPCODE_Y0 = 2, + BZT_BRANCH_OPCODE_X1 = 1, + BZ_BRANCH_OPCODE_X1 = 0, + BZ_OPCODE_SN = 56, + CLZ_UN_0_SHUN_0_OPCODE_X0 = 3, + CLZ_UN_0_SHUN_0_OPCODE_Y0 = 3, + CRC32_32_SPECIAL_0_OPCODE_X0 = 9, + CRC32_8_SPECIAL_0_OPCODE_X0 = 10, + CTZ_UN_0_SHUN_0_OPCODE_X0 = 4, + CTZ_UN_0_SHUN_0_OPCODE_Y0 = 4, + DRAIN_UN_0_SHUN_0_OPCODE_X1 = 1, + DTLBPR_UN_0_SHUN_0_OPCODE_X1 = 2, + DWORD_ALIGN_SPECIAL_0_OPCODE_X0 = 95, + FINV_UN_0_SHUN_0_OPCODE_X1 = 3, + FLUSH_UN_0_SHUN_0_OPCODE_X1 = 4, + FNOP_NOREG_RR_IMM_0_OPCODE_SN = 3, + FNOP_UN_0_SHUN_0_OPCODE_X0 = 5, + FNOP_UN_0_SHUN_0_OPCODE_X1 = 5, + FNOP_UN_0_SHUN_0_OPCODE_Y0 = 5, + FNOP_UN_0_SHUN_0_OPCODE_Y1 = 1, + HALT_NOREG_RR_IMM_0_OPCODE_SN = 0, + ICOH_UN_0_SHUN_0_OPCODE_X1 = 6, + ILL_UN_0_SHUN_0_OPCODE_X1 = 7, + ILL_UN_0_SHUN_0_OPCODE_Y1 = 2, + IMM_0_OPCODE_SN = 0, + IMM_0_OPCODE_X0 = 4, + IMM_0_OPCODE_X1 = 6, + IMM_1_OPCODE_SN = 1, + IMM_OPCODE_0_X0 = 5, + INTHB_SPECIAL_0_OPCODE_X0 = 11, + INTHB_SPECIAL_0_OPCODE_X1 = 5, + INTHH_SPECIAL_0_OPCODE_X0 = 12, + INTHH_SPECIAL_0_OPCODE_X1 = 6, + INTLB_SPECIAL_0_OPCODE_X0 = 13, + INTLB_SPECIAL_0_OPCODE_X1 = 7, + INTLH_SPECIAL_0_OPCODE_X0 = 14, + INTLH_SPECIAL_0_OPCODE_X1 = 8, + INV_UN_0_SHUN_0_OPCODE_X1 = 8, + IRET_UN_0_SHUN_0_OPCODE_X1 = 9, + JALB_OPCODE_X1 = 13, + JALF_OPCODE_X1 = 12, + JALRP_SPECIAL_0_OPCODE_X1 = 9, + JALRR_IMM_1_OPCODE_SN = 3, + JALR_RR_IMM_0_OPCODE_SN = 5, + JALR_SPECIAL_0_OPCODE_X1 = 10, + JB_OPCODE_X1 = 11, + JF_OPCODE_X1 = 10, + JRP_SPECIAL_0_OPCODE_X1 = 11, + JRR_IMM_1_OPCODE_SN = 2, + JR_RR_IMM_0_OPCODE_SN = 4, + JR_SPECIAL_0_OPCODE_X1 = 12, + LBADD_IMM_0_OPCODE_X1 = 22, + LBADD_U_IMM_0_OPCODE_X1 = 23, + LB_OPCODE_Y2 = 0, + LB_UN_0_SHUN_0_OPCODE_X1 = 10, + LB_U_OPCODE_Y2 = 1, + LB_U_UN_0_SHUN_0_OPCODE_X1 = 11, + LHADD_IMM_0_OPCODE_X1 = 24, + LHADD_U_IMM_0_OPCODE_X1 = 25, + LH_OPCODE_Y2 = 2, + LH_UN_0_SHUN_0_OPCODE_X1 = 12, + LH_U_OPCODE_Y2 = 3, + LH_U_UN_0_SHUN_0_OPCODE_X1 = 13, + LNK_SPECIAL_0_OPCODE_X1 = 13, + LWADD_IMM_0_OPCODE_X1 = 26, + LWADD_NA_IMM_0_OPCODE_X1 = 27, + LW_NA_UN_0_SHUN_0_OPCODE_X1 = 24, + LW_OPCODE_Y2 = 4, + LW_UN_0_SHUN_0_OPCODE_X1 = 14, + MAXB_U_SPECIAL_0_OPCODE_X0 = 15, + MAXB_U_SPECIAL_0_OPCODE_X1 = 14, + MAXH_SPECIAL_0_OPCODE_X0 = 16, + MAXH_SPECIAL_0_OPCODE_X1 = 15, + MAXIB_U_IMM_0_OPCODE_X0 = 4, + MAXIB_U_IMM_0_OPCODE_X1 = 5, + MAXIH_IMM_0_OPCODE_X0 = 5, + MAXIH_IMM_0_OPCODE_X1 = 6, + MFSPR_IMM_0_OPCODE_X1 = 7, + MF_UN_0_SHUN_0_OPCODE_X1 = 15, + MINB_U_SPECIAL_0_OPCODE_X0 = 17, + MINB_U_SPECIAL_0_OPCODE_X1 = 16, + MINH_SPECIAL_0_OPCODE_X0 = 18, + MINH_SPECIAL_0_OPCODE_X1 = 17, + MINIB_U_IMM_0_OPCODE_X0 = 6, + MINIB_U_IMM_0_OPCODE_X1 = 8, + MINIH_IMM_0_OPCODE_X0 = 7, + MINIH_IMM_0_OPCODE_X1 = 9, + MM_OPCODE_X0 = 6, + MM_OPCODE_X1 = 7, + MNZB_SPECIAL_0_OPCODE_X0 = 19, + MNZB_SPECIAL_0_OPCODE_X1 = 18, + MNZH_SPECIAL_0_OPCODE_X0 = 20, + MNZH_SPECIAL_0_OPCODE_X1 = 19, + MNZ_SPECIAL_0_OPCODE_X0 = 21, + MNZ_SPECIAL_0_OPCODE_X1 = 20, + MNZ_SPECIAL_1_OPCODE_Y0 = 0, + MNZ_SPECIAL_1_OPCODE_Y1 = 1, + MOVEI_IMM_1_OPCODE_SN = 0, + MOVE_RR_IMM_0_OPCODE_SN = 8, + MTSPR_IMM_0_OPCODE_X1 = 10, + MULHHA_SS_SPECIAL_0_OPCODE_X0 = 22, + MULHHA_SS_SPECIAL_7_OPCODE_Y0 = 0, + MULHHA_SU_SPECIAL_0_OPCODE_X0 = 23, + MULHHA_UU_SPECIAL_0_OPCODE_X0 = 24, + MULHHA_UU_SPECIAL_7_OPCODE_Y0 = 1, + MULHHSA_UU_SPECIAL_0_OPCODE_X0 = 25, + MULHH_SS_SPECIAL_0_OPCODE_X0 = 26, + MULHH_SS_SPECIAL_6_OPCODE_Y0 = 0, + MULHH_SU_SPECIAL_0_OPCODE_X0 = 27, + MULHH_UU_SPECIAL_0_OPCODE_X0 = 28, + MULHH_UU_SPECIAL_6_OPCODE_Y0 = 1, + MULHLA_SS_SPECIAL_0_OPCODE_X0 = 29, + MULHLA_SU_SPECIAL_0_OPCODE_X0 = 30, + MULHLA_US_SPECIAL_0_OPCODE_X0 = 31, + MULHLA_UU_SPECIAL_0_OPCODE_X0 = 32, + MULHLSA_UU_SPECIAL_0_OPCODE_X0 = 33, + MULHLSA_UU_SPECIAL_5_OPCODE_Y0 = 0, + MULHL_SS_SPECIAL_0_OPCODE_X0 = 34, + MULHL_SU_SPECIAL_0_OPCODE_X0 = 35, + MULHL_US_SPECIAL_0_OPCODE_X0 = 36, + MULHL_UU_SPECIAL_0_OPCODE_X0 = 37, + MULLLA_SS_SPECIAL_0_OPCODE_X0 = 38, + MULLLA_SS_SPECIAL_7_OPCODE_Y0 = 2, + MULLLA_SU_SPECIAL_0_OPCODE_X0 = 39, + MULLLA_UU_SPECIAL_0_OPCODE_X0 = 40, + MULLLA_UU_SPECIAL_7_OPCODE_Y0 = 3, + MULLLSA_UU_SPECIAL_0_OPCODE_X0 = 41, + MULLL_SS_SPECIAL_0_OPCODE_X0 = 42, + MULLL_SS_SPECIAL_6_OPCODE_Y0 = 2, + MULLL_SU_SPECIAL_0_OPCODE_X0 = 43, + MULLL_UU_SPECIAL_0_OPCODE_X0 = 44, + MULLL_UU_SPECIAL_6_OPCODE_Y0 = 3, + MVNZ_SPECIAL_0_OPCODE_X0 = 45, + MVNZ_SPECIAL_1_OPCODE_Y0 = 1, + MVZ_SPECIAL_0_OPCODE_X0 = 46, + MVZ_SPECIAL_1_OPCODE_Y0 = 2, + MZB_SPECIAL_0_OPCODE_X0 = 47, + MZB_SPECIAL_0_OPCODE_X1 = 21, + MZH_SPECIAL_0_OPCODE_X0 = 48, + MZH_SPECIAL_0_OPCODE_X1 = 22, + MZ_SPECIAL_0_OPCODE_X0 = 49, + MZ_SPECIAL_0_OPCODE_X1 = 23, + MZ_SPECIAL_1_OPCODE_Y0 = 3, + MZ_SPECIAL_1_OPCODE_Y1 = 2, + NAP_UN_0_SHUN_0_OPCODE_X1 = 16, + NOP_NOREG_RR_IMM_0_OPCODE_SN = 2, + NOP_UN_0_SHUN_0_OPCODE_X0 = 6, + NOP_UN_0_SHUN_0_OPCODE_X1 = 17, + NOP_UN_0_SHUN_0_OPCODE_Y0 = 6, + NOP_UN_0_SHUN_0_OPCODE_Y1 = 3, + NOREG_RR_IMM_0_OPCODE_SN = 0, + NOR_SPECIAL_0_OPCODE_X0 = 50, + NOR_SPECIAL_0_OPCODE_X1 = 24, + NOR_SPECIAL_2_OPCODE_Y0 = 1, + NOR_SPECIAL_2_OPCODE_Y1 = 1, + ORI_IMM_0_OPCODE_X0 = 8, + ORI_IMM_0_OPCODE_X1 = 11, + ORI_OPCODE_Y0 = 11, + ORI_OPCODE_Y1 = 9, + OR_SPECIAL_0_OPCODE_X0 = 51, + OR_SPECIAL_0_OPCODE_X1 = 25, + OR_SPECIAL_2_OPCODE_Y0 = 2, + OR_SPECIAL_2_OPCODE_Y1 = 2, + PACKBS_U_SPECIAL_0_OPCODE_X0 = 103, + PACKBS_U_SPECIAL_0_OPCODE_X1 = 73, + PACKHB_SPECIAL_0_OPCODE_X0 = 52, + PACKHB_SPECIAL_0_OPCODE_X1 = 26, + PACKHS_SPECIAL_0_OPCODE_X0 = 102, + PACKHS_SPECIAL_0_OPCODE_X1 = 72, + PACKLB_SPECIAL_0_OPCODE_X0 = 53, + PACKLB_SPECIAL_0_OPCODE_X1 = 27, + PCNT_UN_0_SHUN_0_OPCODE_X0 = 7, + PCNT_UN_0_SHUN_0_OPCODE_Y0 = 7, + RLI_SHUN_0_OPCODE_X0 = 1, + RLI_SHUN_0_OPCODE_X1 = 1, + RLI_SHUN_0_OPCODE_Y0 = 1, + RLI_SHUN_0_OPCODE_Y1 = 1, + RL_SPECIAL_0_OPCODE_X0 = 54, + RL_SPECIAL_0_OPCODE_X1 = 28, + RL_SPECIAL_3_OPCODE_Y0 = 0, + RL_SPECIAL_3_OPCODE_Y1 = 0, + RR_IMM_0_OPCODE_SN = 0, + S1A_SPECIAL_0_OPCODE_X0 = 55, + S1A_SPECIAL_0_OPCODE_X1 = 29, + S1A_SPECIAL_0_OPCODE_Y0 = 1, + S1A_SPECIAL_0_OPCODE_Y1 = 1, + S2A_SPECIAL_0_OPCODE_X0 = 56, + S2A_SPECIAL_0_OPCODE_X1 = 30, + S2A_SPECIAL_0_OPCODE_Y0 = 2, + S2A_SPECIAL_0_OPCODE_Y1 = 2, + S3A_SPECIAL_0_OPCODE_X0 = 57, + S3A_SPECIAL_0_OPCODE_X1 = 31, + S3A_SPECIAL_5_OPCODE_Y0 = 1, + S3A_SPECIAL_5_OPCODE_Y1 = 1, + SADAB_U_SPECIAL_0_OPCODE_X0 = 58, + SADAH_SPECIAL_0_OPCODE_X0 = 59, + SADAH_U_SPECIAL_0_OPCODE_X0 = 60, + SADB_U_SPECIAL_0_OPCODE_X0 = 61, + SADH_SPECIAL_0_OPCODE_X0 = 62, + SADH_U_SPECIAL_0_OPCODE_X0 = 63, + SBADD_IMM_0_OPCODE_X1 = 28, + SB_OPCODE_Y2 = 5, + SB_SPECIAL_0_OPCODE_X1 = 32, + SEQB_SPECIAL_0_OPCODE_X0 = 64, + SEQB_SPECIAL_0_OPCODE_X1 = 33, + SEQH_SPECIAL_0_OPCODE_X0 = 65, + SEQH_SPECIAL_0_OPCODE_X1 = 34, + SEQIB_IMM_0_OPCODE_X0 = 9, + SEQIB_IMM_0_OPCODE_X1 = 12, + SEQIH_IMM_0_OPCODE_X0 = 10, + SEQIH_IMM_0_OPCODE_X1 = 13, + SEQI_IMM_0_OPCODE_X0 = 11, + SEQI_IMM_0_OPCODE_X1 = 14, + SEQI_OPCODE_Y0 = 12, + SEQI_OPCODE_Y1 = 10, + SEQ_SPECIAL_0_OPCODE_X0 = 66, + SEQ_SPECIAL_0_OPCODE_X1 = 35, + SEQ_SPECIAL_5_OPCODE_Y0 = 2, + SEQ_SPECIAL_5_OPCODE_Y1 = 2, + SHADD_IMM_0_OPCODE_X1 = 29, + SHL8II_IMM_0_OPCODE_SN = 3, + SHLB_SPECIAL_0_OPCODE_X0 = 67, + SHLB_SPECIAL_0_OPCODE_X1 = 36, + SHLH_SPECIAL_0_OPCODE_X0 = 68, + SHLH_SPECIAL_0_OPCODE_X1 = 37, + SHLIB_SHUN_0_OPCODE_X0 = 2, + SHLIB_SHUN_0_OPCODE_X1 = 2, + SHLIH_SHUN_0_OPCODE_X0 = 3, + SHLIH_SHUN_0_OPCODE_X1 = 3, + SHLI_SHUN_0_OPCODE_X0 = 4, + SHLI_SHUN_0_OPCODE_X1 = 4, + SHLI_SHUN_0_OPCODE_Y0 = 2, + SHLI_SHUN_0_OPCODE_Y1 = 2, + SHL_SPECIAL_0_OPCODE_X0 = 69, + SHL_SPECIAL_0_OPCODE_X1 = 38, + SHL_SPECIAL_3_OPCODE_Y0 = 1, + SHL_SPECIAL_3_OPCODE_Y1 = 1, + SHR1_RR_IMM_0_OPCODE_SN = 9, + SHRB_SPECIAL_0_OPCODE_X0 = 70, + SHRB_SPECIAL_0_OPCODE_X1 = 39, + SHRH_SPECIAL_0_OPCODE_X0 = 71, + SHRH_SPECIAL_0_OPCODE_X1 = 40, + SHRIB_SHUN_0_OPCODE_X0 = 5, + SHRIB_SHUN_0_OPCODE_X1 = 5, + SHRIH_SHUN_0_OPCODE_X0 = 6, + SHRIH_SHUN_0_OPCODE_X1 = 6, + SHRI_SHUN_0_OPCODE_X0 = 7, + SHRI_SHUN_0_OPCODE_X1 = 7, + SHRI_SHUN_0_OPCODE_Y0 = 3, + SHRI_SHUN_0_OPCODE_Y1 = 3, + SHR_SPECIAL_0_OPCODE_X0 = 72, + SHR_SPECIAL_0_OPCODE_X1 = 41, + SHR_SPECIAL_3_OPCODE_Y0 = 2, + SHR_SPECIAL_3_OPCODE_Y1 = 2, + SHUN_0_OPCODE_X0 = 7, + SHUN_0_OPCODE_X1 = 8, + SHUN_0_OPCODE_Y0 = 13, + SHUN_0_OPCODE_Y1 = 11, + SH_OPCODE_Y2 = 6, + SH_SPECIAL_0_OPCODE_X1 = 42, + SLTB_SPECIAL_0_OPCODE_X0 = 73, + SLTB_SPECIAL_0_OPCODE_X1 = 43, + SLTB_U_SPECIAL_0_OPCODE_X0 = 74, + SLTB_U_SPECIAL_0_OPCODE_X1 = 44, + SLTEB_SPECIAL_0_OPCODE_X0 = 75, + SLTEB_SPECIAL_0_OPCODE_X1 = 45, + SLTEB_U_SPECIAL_0_OPCODE_X0 = 76, + SLTEB_U_SPECIAL_0_OPCODE_X1 = 46, + SLTEH_SPECIAL_0_OPCODE_X0 = 77, + SLTEH_SPECIAL_0_OPCODE_X1 = 47, + SLTEH_U_SPECIAL_0_OPCODE_X0 = 78, + SLTEH_U_SPECIAL_0_OPCODE_X1 = 48, + SLTE_SPECIAL_0_OPCODE_X0 = 79, + SLTE_SPECIAL_0_OPCODE_X1 = 49, + SLTE_SPECIAL_4_OPCODE_Y0 = 0, + SLTE_SPECIAL_4_OPCODE_Y1 = 0, + SLTE_U_SPECIAL_0_OPCODE_X0 = 80, + SLTE_U_SPECIAL_0_OPCODE_X1 = 50, + SLTE_U_SPECIAL_4_OPCODE_Y0 = 1, + SLTE_U_SPECIAL_4_OPCODE_Y1 = 1, + SLTH_SPECIAL_0_OPCODE_X0 = 81, + SLTH_SPECIAL_0_OPCODE_X1 = 51, + SLTH_U_SPECIAL_0_OPCODE_X0 = 82, + SLTH_U_SPECIAL_0_OPCODE_X1 = 52, + SLTIB_IMM_0_OPCODE_X0 = 12, + SLTIB_IMM_0_OPCODE_X1 = 15, + SLTIB_U_IMM_0_OPCODE_X0 = 13, + SLTIB_U_IMM_0_OPCODE_X1 = 16, + SLTIH_IMM_0_OPCODE_X0 = 14, + SLTIH_IMM_0_OPCODE_X1 = 17, + SLTIH_U_IMM_0_OPCODE_X0 = 15, + SLTIH_U_IMM_0_OPCODE_X1 = 18, + SLTI_IMM_0_OPCODE_X0 = 16, + SLTI_IMM_0_OPCODE_X1 = 19, + SLTI_OPCODE_Y0 = 14, + SLTI_OPCODE_Y1 = 12, + SLTI_U_IMM_0_OPCODE_X0 = 17, + SLTI_U_IMM_0_OPCODE_X1 = 20, + SLTI_U_OPCODE_Y0 = 15, + SLTI_U_OPCODE_Y1 = 13, + SLT_SPECIAL_0_OPCODE_X0 = 83, + SLT_SPECIAL_0_OPCODE_X1 = 53, + SLT_SPECIAL_4_OPCODE_Y0 = 2, + SLT_SPECIAL_4_OPCODE_Y1 = 2, + SLT_U_SPECIAL_0_OPCODE_X0 = 84, + SLT_U_SPECIAL_0_OPCODE_X1 = 54, + SLT_U_SPECIAL_4_OPCODE_Y0 = 3, + SLT_U_SPECIAL_4_OPCODE_Y1 = 3, + SNEB_SPECIAL_0_OPCODE_X0 = 85, + SNEB_SPECIAL_0_OPCODE_X1 = 55, + SNEH_SPECIAL_0_OPCODE_X0 = 86, + SNEH_SPECIAL_0_OPCODE_X1 = 56, + SNE_SPECIAL_0_OPCODE_X0 = 87, + SNE_SPECIAL_0_OPCODE_X1 = 57, + SNE_SPECIAL_5_OPCODE_Y0 = 3, + SNE_SPECIAL_5_OPCODE_Y1 = 3, + SPECIAL_0_OPCODE_X0 = 0, + SPECIAL_0_OPCODE_X1 = 1, + SPECIAL_0_OPCODE_Y0 = 1, + SPECIAL_0_OPCODE_Y1 = 1, + SPECIAL_1_OPCODE_Y0 = 2, + SPECIAL_1_OPCODE_Y1 = 2, + SPECIAL_2_OPCODE_Y0 = 3, + SPECIAL_2_OPCODE_Y1 = 3, + SPECIAL_3_OPCODE_Y0 = 4, + SPECIAL_3_OPCODE_Y1 = 4, + SPECIAL_4_OPCODE_Y0 = 5, + SPECIAL_4_OPCODE_Y1 = 5, + SPECIAL_5_OPCODE_Y0 = 6, + SPECIAL_5_OPCODE_Y1 = 6, + SPECIAL_6_OPCODE_Y0 = 7, + SPECIAL_7_OPCODE_Y0 = 8, + SRAB_SPECIAL_0_OPCODE_X0 = 88, + SRAB_SPECIAL_0_OPCODE_X1 = 58, + SRAH_SPECIAL_0_OPCODE_X0 = 89, + SRAH_SPECIAL_0_OPCODE_X1 = 59, + SRAIB_SHUN_0_OPCODE_X0 = 8, + SRAIB_SHUN_0_OPCODE_X1 = 8, + SRAIH_SHUN_0_OPCODE_X0 = 9, + SRAIH_SHUN_0_OPCODE_X1 = 9, + SRAI_SHUN_0_OPCODE_X0 = 10, + SRAI_SHUN_0_OPCODE_X1 = 10, + SRAI_SHUN_0_OPCODE_Y0 = 4, + SRAI_SHUN_0_OPCODE_Y1 = 4, + SRA_SPECIAL_0_OPCODE_X0 = 90, + SRA_SPECIAL_0_OPCODE_X1 = 60, + SRA_SPECIAL_3_OPCODE_Y0 = 3, + SRA_SPECIAL_3_OPCODE_Y1 = 3, + SUBBS_U_SPECIAL_0_OPCODE_X0 = 100, + SUBBS_U_SPECIAL_0_OPCODE_X1 = 70, + SUBB_SPECIAL_0_OPCODE_X0 = 91, + SUBB_SPECIAL_0_OPCODE_X1 = 61, + SUBHS_SPECIAL_0_OPCODE_X0 = 101, + SUBHS_SPECIAL_0_OPCODE_X1 = 71, + SUBH_SPECIAL_0_OPCODE_X0 = 92, + SUBH_SPECIAL_0_OPCODE_X1 = 62, + SUBS_SPECIAL_0_OPCODE_X0 = 97, + SUBS_SPECIAL_0_OPCODE_X1 = 67, + SUB_SPECIAL_0_OPCODE_X0 = 93, + SUB_SPECIAL_0_OPCODE_X1 = 63, + SUB_SPECIAL_0_OPCODE_Y0 = 3, + SUB_SPECIAL_0_OPCODE_Y1 = 3, + SWADD_IMM_0_OPCODE_X1 = 30, + SWINT0_UN_0_SHUN_0_OPCODE_X1 = 18, + SWINT1_UN_0_SHUN_0_OPCODE_X1 = 19, + SWINT2_UN_0_SHUN_0_OPCODE_X1 = 20, + SWINT3_UN_0_SHUN_0_OPCODE_X1 = 21, + SW_OPCODE_Y2 = 7, + SW_SPECIAL_0_OPCODE_X1 = 64, + TBLIDXB0_UN_0_SHUN_0_OPCODE_X0 = 8, + TBLIDXB0_UN_0_SHUN_0_OPCODE_Y0 = 8, + TBLIDXB1_UN_0_SHUN_0_OPCODE_X0 = 9, + TBLIDXB1_UN_0_SHUN_0_OPCODE_Y0 = 9, + TBLIDXB2_UN_0_SHUN_0_OPCODE_X0 = 10, + TBLIDXB2_UN_0_SHUN_0_OPCODE_Y0 = 10, + TBLIDXB3_UN_0_SHUN_0_OPCODE_X0 = 11, + TBLIDXB3_UN_0_SHUN_0_OPCODE_Y0 = 11, + TNS_UN_0_SHUN_0_OPCODE_X1 = 22, + UN_0_SHUN_0_OPCODE_X0 = 11, + UN_0_SHUN_0_OPCODE_X1 = 11, + UN_0_SHUN_0_OPCODE_Y0 = 5, + UN_0_SHUN_0_OPCODE_Y1 = 5, + WH64_UN_0_SHUN_0_OPCODE_X1 = 23, + XORI_IMM_0_OPCODE_X0 = 2, + XORI_IMM_0_OPCODE_X1 = 21, + XOR_SPECIAL_0_OPCODE_X0 = 94, + XOR_SPECIAL_0_OPCODE_X1 = 65, + XOR_SPECIAL_2_OPCODE_Y0 = 3, + XOR_SPECIAL_2_OPCODE_Y1 = 3 +}; + + +#endif /* __ASSEMBLER__ */ + +#endif /* __ARCH_OPCODE_H__ */ diff --git a/arch/tile/include/asm/opcode-tile_32.h b/arch/tile/include/asm/opcode-tile_32.h deleted file mode 100644 index 03df7b1e77bf..000000000000 --- a/arch/tile/include/asm/opcode-tile_32.h +++ /dev/null @@ -1,1513 +0,0 @@ -/* tile.h -- Header file for TILE opcode table - Copyright (C) 2005 Free Software Foundation, Inc. - Contributed by Tilera Corp. */ - -#ifndef opcode_tile_h -#define opcode_tile_h - -typedef unsigned long long tile_bundle_bits; - - -enum -{ - TILE_MAX_OPERANDS = 5 /* mm */ -}; - -typedef enum -{ - TILE_OPC_BPT, - TILE_OPC_INFO, - TILE_OPC_INFOL, - TILE_OPC_J, - TILE_OPC_JAL, - TILE_OPC_MOVE, - TILE_OPC_MOVE_SN, - TILE_OPC_MOVEI, - TILE_OPC_MOVEI_SN, - TILE_OPC_MOVELI, - TILE_OPC_MOVELI_SN, - TILE_OPC_MOVELIS, - TILE_OPC_PREFETCH, - TILE_OPC_RAISE, - TILE_OPC_ADD, - TILE_OPC_ADD_SN, - TILE_OPC_ADDB, - TILE_OPC_ADDB_SN, - TILE_OPC_ADDBS_U, - TILE_OPC_ADDBS_U_SN, - TILE_OPC_ADDH, - TILE_OPC_ADDH_SN, - TILE_OPC_ADDHS, - TILE_OPC_ADDHS_SN, - TILE_OPC_ADDI, - TILE_OPC_ADDI_SN, - TILE_OPC_ADDIB, - TILE_OPC_ADDIB_SN, - TILE_OPC_ADDIH, - TILE_OPC_ADDIH_SN, - TILE_OPC_ADDLI, - TILE_OPC_ADDLI_SN, - TILE_OPC_ADDLIS, - TILE_OPC_ADDS, - TILE_OPC_ADDS_SN, - TILE_OPC_ADIFFB_U, - TILE_OPC_ADIFFB_U_SN, - TILE_OPC_ADIFFH, - TILE_OPC_ADIFFH_SN, - TILE_OPC_AND, - TILE_OPC_AND_SN, - TILE_OPC_ANDI, - TILE_OPC_ANDI_SN, - TILE_OPC_AULI, - TILE_OPC_AVGB_U, - TILE_OPC_AVGB_U_SN, - TILE_OPC_AVGH, - TILE_OPC_AVGH_SN, - TILE_OPC_BBNS, - TILE_OPC_BBNS_SN, - TILE_OPC_BBNST, - TILE_OPC_BBNST_SN, - TILE_OPC_BBS, - TILE_OPC_BBS_SN, - TILE_OPC_BBST, - TILE_OPC_BBST_SN, - TILE_OPC_BGEZ, - TILE_OPC_BGEZ_SN, - TILE_OPC_BGEZT, - TILE_OPC_BGEZT_SN, - TILE_OPC_BGZ, - TILE_OPC_BGZ_SN, - TILE_OPC_BGZT, - TILE_OPC_BGZT_SN, - TILE_OPC_BITX, - TILE_OPC_BITX_SN, - TILE_OPC_BLEZ, - TILE_OPC_BLEZ_SN, - TILE_OPC_BLEZT, - TILE_OPC_BLEZT_SN, - TILE_OPC_BLZ, - TILE_OPC_BLZ_SN, - TILE_OPC_BLZT, - TILE_OPC_BLZT_SN, - TILE_OPC_BNZ, - TILE_OPC_BNZ_SN, - TILE_OPC_BNZT, - TILE_OPC_BNZT_SN, - TILE_OPC_BYTEX, - TILE_OPC_BYTEX_SN, - TILE_OPC_BZ, - TILE_OPC_BZ_SN, - TILE_OPC_BZT, - TILE_OPC_BZT_SN, - TILE_OPC_CLZ, - TILE_OPC_CLZ_SN, - TILE_OPC_CRC32_32, - TILE_OPC_CRC32_32_SN, - TILE_OPC_CRC32_8, - TILE_OPC_CRC32_8_SN, - TILE_OPC_CTZ, - TILE_OPC_CTZ_SN, - TILE_OPC_DRAIN, - TILE_OPC_DTLBPR, - TILE_OPC_DWORD_ALIGN, - TILE_OPC_DWORD_ALIGN_SN, - TILE_OPC_FINV, - TILE_OPC_FLUSH, - TILE_OPC_FNOP, - TILE_OPC_ICOH, - TILE_OPC_ILL, - TILE_OPC_INTHB, - TILE_OPC_INTHB_SN, - TILE_OPC_INTHH, - TILE_OPC_INTHH_SN, - TILE_OPC_INTLB, - TILE_OPC_INTLB_SN, - TILE_OPC_INTLH, - TILE_OPC_INTLH_SN, - TILE_OPC_INV, - TILE_OPC_IRET, - TILE_OPC_JALB, - TILE_OPC_JALF, - TILE_OPC_JALR, - TILE_OPC_JALRP, - TILE_OPC_JB, - TILE_OPC_JF, - TILE_OPC_JR, - TILE_OPC_JRP, - TILE_OPC_LB, - TILE_OPC_LB_SN, - TILE_OPC_LB_U, - TILE_OPC_LB_U_SN, - TILE_OPC_LBADD, - TILE_OPC_LBADD_SN, - TILE_OPC_LBADD_U, - TILE_OPC_LBADD_U_SN, - TILE_OPC_LH, - TILE_OPC_LH_SN, - TILE_OPC_LH_U, - TILE_OPC_LH_U_SN, - TILE_OPC_LHADD, - TILE_OPC_LHADD_SN, - TILE_OPC_LHADD_U, - TILE_OPC_LHADD_U_SN, - TILE_OPC_LNK, - TILE_OPC_LNK_SN, - TILE_OPC_LW, - TILE_OPC_LW_SN, - TILE_OPC_LW_NA, - TILE_OPC_LW_NA_SN, - TILE_OPC_LWADD, - TILE_OPC_LWADD_SN, - TILE_OPC_LWADD_NA, - TILE_OPC_LWADD_NA_SN, - TILE_OPC_MAXB_U, - TILE_OPC_MAXB_U_SN, - TILE_OPC_MAXH, - TILE_OPC_MAXH_SN, - TILE_OPC_MAXIB_U, - TILE_OPC_MAXIB_U_SN, - TILE_OPC_MAXIH, - TILE_OPC_MAXIH_SN, - TILE_OPC_MF, - TILE_OPC_MFSPR, - TILE_OPC_MINB_U, - TILE_OPC_MINB_U_SN, - TILE_OPC_MINH, - TILE_OPC_MINH_SN, - TILE_OPC_MINIB_U, - TILE_OPC_MINIB_U_SN, - TILE_OPC_MINIH, - TILE_OPC_MINIH_SN, - TILE_OPC_MM, - TILE_OPC_MNZ, - TILE_OPC_MNZ_SN, - TILE_OPC_MNZB, - TILE_OPC_MNZB_SN, - TILE_OPC_MNZH, - TILE_OPC_MNZH_SN, - TILE_OPC_MTSPR, - TILE_OPC_MULHH_SS, - TILE_OPC_MULHH_SS_SN, - TILE_OPC_MULHH_SU, - TILE_OPC_MULHH_SU_SN, - TILE_OPC_MULHH_UU, - TILE_OPC_MULHH_UU_SN, - TILE_OPC_MULHHA_SS, - TILE_OPC_MULHHA_SS_SN, - TILE_OPC_MULHHA_SU, - TILE_OPC_MULHHA_SU_SN, - TILE_OPC_MULHHA_UU, - TILE_OPC_MULHHA_UU_SN, - TILE_OPC_MULHHSA_UU, - TILE_OPC_MULHHSA_UU_SN, - TILE_OPC_MULHL_SS, - TILE_OPC_MULHL_SS_SN, - TILE_OPC_MULHL_SU, - TILE_OPC_MULHL_SU_SN, - TILE_OPC_MULHL_US, - TILE_OPC_MULHL_US_SN, - TILE_OPC_MULHL_UU, - TILE_OPC_MULHL_UU_SN, - TILE_OPC_MULHLA_SS, - TILE_OPC_MULHLA_SS_SN, - TILE_OPC_MULHLA_SU, - TILE_OPC_MULHLA_SU_SN, - TILE_OPC_MULHLA_US, - TILE_OPC_MULHLA_US_SN, - TILE_OPC_MULHLA_UU, - TILE_OPC_MULHLA_UU_SN, - TILE_OPC_MULHLSA_UU, - TILE_OPC_MULHLSA_UU_SN, - TILE_OPC_MULLL_SS, - TILE_OPC_MULLL_SS_SN, - TILE_OPC_MULLL_SU, - TILE_OPC_MULLL_SU_SN, - TILE_OPC_MULLL_UU, - TILE_OPC_MULLL_UU_SN, - TILE_OPC_MULLLA_SS, - TILE_OPC_MULLLA_SS_SN, - TILE_OPC_MULLLA_SU, - TILE_OPC_MULLLA_SU_SN, - TILE_OPC_MULLLA_UU, - TILE_OPC_MULLLA_UU_SN, - TILE_OPC_MULLLSA_UU, - TILE_OPC_MULLLSA_UU_SN, - TILE_OPC_MVNZ, - TILE_OPC_MVNZ_SN, - TILE_OPC_MVZ, - TILE_OPC_MVZ_SN, - TILE_OPC_MZ, - TILE_OPC_MZ_SN, - TILE_OPC_MZB, - TILE_OPC_MZB_SN, - TILE_OPC_MZH, - TILE_OPC_MZH_SN, - TILE_OPC_NAP, - TILE_OPC_NOP, - TILE_OPC_NOR, - TILE_OPC_NOR_SN, - TILE_OPC_OR, - TILE_OPC_OR_SN, - TILE_OPC_ORI, - TILE_OPC_ORI_SN, - TILE_OPC_PACKBS_U, - TILE_OPC_PACKBS_U_SN, - TILE_OPC_PACKHB, - TILE_OPC_PACKHB_SN, - TILE_OPC_PACKHS, - TILE_OPC_PACKHS_SN, - TILE_OPC_PACKLB, - TILE_OPC_PACKLB_SN, - TILE_OPC_PCNT, - TILE_OPC_PCNT_SN, - TILE_OPC_RL, - TILE_OPC_RL_SN, - TILE_OPC_RLI, - TILE_OPC_RLI_SN, - TILE_OPC_S1A, - TILE_OPC_S1A_SN, - TILE_OPC_S2A, - TILE_OPC_S2A_SN, - TILE_OPC_S3A, - TILE_OPC_S3A_SN, - TILE_OPC_SADAB_U, - TILE_OPC_SADAB_U_SN, - TILE_OPC_SADAH, - TILE_OPC_SADAH_SN, - TILE_OPC_SADAH_U, - TILE_OPC_SADAH_U_SN, - TILE_OPC_SADB_U, - TILE_OPC_SADB_U_SN, - TILE_OPC_SADH, - TILE_OPC_SADH_SN, - TILE_OPC_SADH_U, - TILE_OPC_SADH_U_SN, - TILE_OPC_SB, - TILE_OPC_SBADD, - TILE_OPC_SEQ, - TILE_OPC_SEQ_SN, - TILE_OPC_SEQB, - TILE_OPC_SEQB_SN, - TILE_OPC_SEQH, - TILE_OPC_SEQH_SN, - TILE_OPC_SEQI, - TILE_OPC_SEQI_SN, - TILE_OPC_SEQIB, - TILE_OPC_SEQIB_SN, - TILE_OPC_SEQIH, - TILE_OPC_SEQIH_SN, - TILE_OPC_SH, - TILE_OPC_SHADD, - TILE_OPC_SHL, - TILE_OPC_SHL_SN, - TILE_OPC_SHLB, - TILE_OPC_SHLB_SN, - TILE_OPC_SHLH, - TILE_OPC_SHLH_SN, - TILE_OPC_SHLI, - TILE_OPC_SHLI_SN, - TILE_OPC_SHLIB, - TILE_OPC_SHLIB_SN, - TILE_OPC_SHLIH, - TILE_OPC_SHLIH_SN, - TILE_OPC_SHR, - TILE_OPC_SHR_SN, - TILE_OPC_SHRB, - TILE_OPC_SHRB_SN, - TILE_OPC_SHRH, - TILE_OPC_SHRH_SN, - TILE_OPC_SHRI, - TILE_OPC_SHRI_SN, - TILE_OPC_SHRIB, - TILE_OPC_SHRIB_SN, - TILE_OPC_SHRIH, - TILE_OPC_SHRIH_SN, - TILE_OPC_SLT, - TILE_OPC_SLT_SN, - TILE_OPC_SLT_U, - TILE_OPC_SLT_U_SN, - TILE_OPC_SLTB, - TILE_OPC_SLTB_SN, - TILE_OPC_SLTB_U, - TILE_OPC_SLTB_U_SN, - TILE_OPC_SLTE, - TILE_OPC_SLTE_SN, - TILE_OPC_SLTE_U, - TILE_OPC_SLTE_U_SN, - TILE_OPC_SLTEB, - TILE_OPC_SLTEB_SN, - TILE_OPC_SLTEB_U, - TILE_OPC_SLTEB_U_SN, - TILE_OPC_SLTEH, - TILE_OPC_SLTEH_SN, - TILE_OPC_SLTEH_U, - TILE_OPC_SLTEH_U_SN, - TILE_OPC_SLTH, - TILE_OPC_SLTH_SN, - TILE_OPC_SLTH_U, - TILE_OPC_SLTH_U_SN, - TILE_OPC_SLTI, - TILE_OPC_SLTI_SN, - TILE_OPC_SLTI_U, - TILE_OPC_SLTI_U_SN, - TILE_OPC_SLTIB, - TILE_OPC_SLTIB_SN, - TILE_OPC_SLTIB_U, - TILE_OPC_SLTIB_U_SN, - TILE_OPC_SLTIH, - TILE_OPC_SLTIH_SN, - TILE_OPC_SLTIH_U, - TILE_OPC_SLTIH_U_SN, - TILE_OPC_SNE, - TILE_OPC_SNE_SN, - TILE_OPC_SNEB, - TILE_OPC_SNEB_SN, - TILE_OPC_SNEH, - TILE_OPC_SNEH_SN, - TILE_OPC_SRA, - TILE_OPC_SRA_SN, - TILE_OPC_SRAB, - TILE_OPC_SRAB_SN, - TILE_OPC_SRAH, - TILE_OPC_SRAH_SN, - TILE_OPC_SRAI, - TILE_OPC_SRAI_SN, - TILE_OPC_SRAIB, - TILE_OPC_SRAIB_SN, - TILE_OPC_SRAIH, - TILE_OPC_SRAIH_SN, - TILE_OPC_SUB, - TILE_OPC_SUB_SN, - TILE_OPC_SUBB, - TILE_OPC_SUBB_SN, - TILE_OPC_SUBBS_U, - TILE_OPC_SUBBS_U_SN, - TILE_OPC_SUBH, - TILE_OPC_SUBH_SN, - TILE_OPC_SUBHS, - TILE_OPC_SUBHS_SN, - TILE_OPC_SUBS, - TILE_OPC_SUBS_SN, - TILE_OPC_SW, - TILE_OPC_SWADD, - TILE_OPC_SWINT0, - TILE_OPC_SWINT1, - TILE_OPC_SWINT2, - TILE_OPC_SWINT3, - TILE_OPC_TBLIDXB0, - TILE_OPC_TBLIDXB0_SN, - TILE_OPC_TBLIDXB1, - TILE_OPC_TBLIDXB1_SN, - TILE_OPC_TBLIDXB2, - TILE_OPC_TBLIDXB2_SN, - TILE_OPC_TBLIDXB3, - TILE_OPC_TBLIDXB3_SN, - TILE_OPC_TNS, - TILE_OPC_TNS_SN, - TILE_OPC_WH64, - TILE_OPC_XOR, - TILE_OPC_XOR_SN, - TILE_OPC_XORI, - TILE_OPC_XORI_SN, - TILE_OPC_NONE -} tile_mnemonic; - -/* 64-bit pattern for a { bpt ; nop } bundle. */ -#define TILE_BPT_BUNDLE 0x400b3cae70166000ULL - - -#define TILE_ELF_MACHINE_CODE EM_TILEPRO - -#define TILE_ELF_NAME "elf32-tilepro" - - -static __inline unsigned int -get_BrOff_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3ff); -} - -static __inline unsigned int -get_BrOff_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x00007fff) | - (((unsigned int)(n >> 20)) & 0x00018000); -} - -static __inline unsigned int -get_BrType_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0xf); -} - -static __inline unsigned int -get_Dest_Imm8_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 43)) & 0x000000c0); -} - -static __inline unsigned int -get_Dest_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 2)) & 0x3); -} - -static __inline unsigned int -get_Dest_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3f); -} - -static __inline unsigned int -get_Dest_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x3f); -} - -static __inline unsigned int -get_Dest_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3f); -} - -static __inline unsigned int -get_Dest_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x3f); -} - -static __inline unsigned int -get_Imm16_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xffff); -} - -static __inline unsigned int -get_Imm16_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xffff); -} - -static __inline unsigned int -get_Imm8_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0xff); -} - -static __inline unsigned int -get_Imm8_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xff); -} - -static __inline unsigned int -get_Imm8_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xff); -} - -static __inline unsigned int -get_Imm8_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xff); -} - -static __inline unsigned int -get_Imm8_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xff); -} - -static __inline unsigned int -get_ImmOpcodeExtension_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 20)) & 0x7f); -} - -static __inline unsigned int -get_ImmOpcodeExtension_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 51)) & 0x7f); -} - -static __inline unsigned int -get_ImmRROpcodeExtension_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 8)) & 0x3); -} - -static __inline unsigned int -get_JOffLong_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x00007fff) | - (((unsigned int)(n >> 20)) & 0x00018000) | - (((unsigned int)(n >> 14)) & 0x001e0000) | - (((unsigned int)(n >> 16)) & 0x07e00000) | - (((unsigned int)(n >> 31)) & 0x18000000); -} - -static __inline unsigned int -get_JOff_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x00007fff) | - (((unsigned int)(n >> 20)) & 0x00018000) | - (((unsigned int)(n >> 14)) & 0x001e0000) | - (((unsigned int)(n >> 16)) & 0x07e00000) | - (((unsigned int)(n >> 31)) & 0x08000000); -} - -static __inline unsigned int -get_MF_Imm15_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x00003fff) | - (((unsigned int)(n >> 44)) & 0x00004000); -} - -static __inline unsigned int -get_MMEnd_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x1f); -} - -static __inline unsigned int -get_MMEnd_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x1f); -} - -static __inline unsigned int -get_MMStart_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 23)) & 0x1f); -} - -static __inline unsigned int -get_MMStart_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 54)) & 0x1f); -} - -static __inline unsigned int -get_MT_Imm15_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 37)) & 0x00003fc0) | - (((unsigned int)(n >> 44)) & 0x00004000); -} - -static __inline unsigned int -get_Mode(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 63)) & 0x1); -} - -static __inline unsigned int -get_NoRegOpcodeExtension_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0xf); -} - -static __inline unsigned int -get_Opcode_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 10)) & 0x3f); -} - -static __inline unsigned int -get_Opcode_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 28)) & 0x7); -} - -static __inline unsigned int -get_Opcode_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 59)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 27)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 59)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y2(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 56)) & 0x7); -} - -static __inline unsigned int -get_RROpcodeExtension_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 4)) & 0xf); -} - -static __inline unsigned int -get_RRROpcodeExtension_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x1ff); -} - -static __inline unsigned int -get_RRROpcodeExtension_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x1ff); -} - -static __inline unsigned int -get_RRROpcodeExtension_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3); -} - -static __inline unsigned int -get_RRROpcodeExtension_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3); -} - -static __inline unsigned int -get_RouteOpcodeExtension_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3ff); -} - -static __inline unsigned int -get_S_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 27)) & 0x1); -} - -static __inline unsigned int -get_S_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 58)) & 0x1); -} - -static __inline unsigned int -get_ShAmt_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x1f); -} - -static __inline unsigned int -get_ShAmt_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x1f); -} - -static __inline unsigned int -get_ShAmt_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x1f); -} - -static __inline unsigned int -get_ShAmt_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x1f); -} - -static __inline unsigned int -get_SrcA_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 6)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 6)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y2(tile_bundle_bits n) -{ - return (((n >> 26)) & 0x00000001) | - (((unsigned int)(n >> 50)) & 0x0000003e); -} - -static __inline unsigned int -get_SrcBDest_Y2(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 20)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_Src_SN(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3); -} - -static __inline unsigned int -get_UnOpcodeExtension_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x1f); -} - -static __inline unsigned int -get_UnOpcodeExtension_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x1f); -} - -static __inline unsigned int -get_UnOpcodeExtension_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x1f); -} - -static __inline unsigned int -get_UnOpcodeExtension_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x1f); -} - -static __inline unsigned int -get_UnShOpcodeExtension_X0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 17)) & 0x3ff); -} - -static __inline unsigned int -get_UnShOpcodeExtension_X1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 48)) & 0x3ff); -} - -static __inline unsigned int -get_UnShOpcodeExtension_Y0(tile_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 17)) & 0x7); -} - -static __inline unsigned int -get_UnShOpcodeExtension_Y1(tile_bundle_bits n) -{ - return (((unsigned int)(n >> 48)) & 0x7); -} - - -static __inline int -sign_extend(int n, int num_bits) -{ - int shift = (int)(sizeof(int) * 8 - num_bits); - return (n << shift) >> shift; -} - - - -static __inline tile_bundle_bits -create_BrOff_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 0); -} - -static __inline tile_bundle_bits -create_BrOff_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x00007fff)) << 43) | - (((tile_bundle_bits)(n & 0x00018000)) << 20); -} - -static __inline tile_bundle_bits -create_BrType_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0xf)) << 31); -} - -static __inline tile_bundle_bits -create_Dest_Imm8_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x0000003f)) << 31) | - (((tile_bundle_bits)(n & 0x000000c0)) << 43); -} - -static __inline tile_bundle_bits -create_Dest_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 2); -} - -static __inline tile_bundle_bits -create_Dest_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 0); -} - -static __inline tile_bundle_bits -create_Dest_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x3f)) << 31); -} - -static __inline tile_bundle_bits -create_Dest_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 0); -} - -static __inline tile_bundle_bits -create_Dest_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x3f)) << 31); -} - -static __inline tile_bundle_bits -create_Imm16_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xffff) << 12); -} - -static __inline tile_bundle_bits -create_Imm16_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0xffff)) << 43); -} - -static __inline tile_bundle_bits -create_Imm8_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 0); -} - -static __inline tile_bundle_bits -create_Imm8_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 12); -} - -static __inline tile_bundle_bits -create_Imm8_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0xff)) << 43); -} - -static __inline tile_bundle_bits -create_Imm8_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 12); -} - -static __inline tile_bundle_bits -create_Imm8_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0xff)) << 43); -} - -static __inline tile_bundle_bits -create_ImmOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x7f) << 20); -} - -static __inline tile_bundle_bits -create_ImmOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x7f)) << 51); -} - -static __inline tile_bundle_bits -create_ImmRROpcodeExtension_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 8); -} - -static __inline tile_bundle_bits -create_JOffLong_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x00007fff)) << 43) | - (((tile_bundle_bits)(n & 0x00018000)) << 20) | - (((tile_bundle_bits)(n & 0x001e0000)) << 14) | - (((tile_bundle_bits)(n & 0x07e00000)) << 16) | - (((tile_bundle_bits)(n & 0x18000000)) << 31); -} - -static __inline tile_bundle_bits -create_JOff_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x00007fff)) << 43) | - (((tile_bundle_bits)(n & 0x00018000)) << 20) | - (((tile_bundle_bits)(n & 0x001e0000)) << 14) | - (((tile_bundle_bits)(n & 0x07e00000)) << 16) | - (((tile_bundle_bits)(n & 0x08000000)) << 31); -} - -static __inline tile_bundle_bits -create_MF_Imm15_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x00003fff)) << 37) | - (((tile_bundle_bits)(n & 0x00004000)) << 44); -} - -static __inline tile_bundle_bits -create_MMEnd_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 18); -} - -static __inline tile_bundle_bits -create_MMEnd_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1f)) << 49); -} - -static __inline tile_bundle_bits -create_MMStart_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 23); -} - -static __inline tile_bundle_bits -create_MMStart_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1f)) << 54); -} - -static __inline tile_bundle_bits -create_MT_Imm15_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x0000003f)) << 31) | - (((tile_bundle_bits)(n & 0x00003fc0)) << 37) | - (((tile_bundle_bits)(n & 0x00004000)) << 44); -} - -static __inline tile_bundle_bits -create_Mode(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1)) << 63); -} - -static __inline tile_bundle_bits -create_NoRegOpcodeExtension_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 0); -} - -static __inline tile_bundle_bits -create_Opcode_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 10); -} - -static __inline tile_bundle_bits -create_Opcode_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x7) << 28); -} - -static __inline tile_bundle_bits -create_Opcode_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0xf)) << 59); -} - -static __inline tile_bundle_bits -create_Opcode_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 27); -} - -static __inline tile_bundle_bits -create_Opcode_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0xf)) << 59); -} - -static __inline tile_bundle_bits -create_Opcode_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x7)) << 56); -} - -static __inline tile_bundle_bits -create_RROpcodeExtension_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 4); -} - -static __inline tile_bundle_bits -create_RRROpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1ff) << 18); -} - -static __inline tile_bundle_bits -create_RRROpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1ff)) << 49); -} - -static __inline tile_bundle_bits -create_RRROpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 18); -} - -static __inline tile_bundle_bits -create_RRROpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x3)) << 49); -} - -static __inline tile_bundle_bits -create_RouteOpcodeExtension_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 0); -} - -static __inline tile_bundle_bits -create_S_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1) << 27); -} - -static __inline tile_bundle_bits -create_S_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1)) << 58); -} - -static __inline tile_bundle_bits -create_ShAmt_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 12); -} - -static __inline tile_bundle_bits -create_ShAmt_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1f)) << 43); -} - -static __inline tile_bundle_bits -create_ShAmt_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 12); -} - -static __inline tile_bundle_bits -create_ShAmt_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1f)) << 43); -} - -static __inline tile_bundle_bits -create_SrcA_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 6); -} - -static __inline tile_bundle_bits -create_SrcA_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x3f)) << 37); -} - -static __inline tile_bundle_bits -create_SrcA_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 6); -} - -static __inline tile_bundle_bits -create_SrcA_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x3f)) << 37); -} - -static __inline tile_bundle_bits -create_SrcA_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x00000001) << 26) | - (((tile_bundle_bits)(n & 0x0000003e)) << 50); -} - -static __inline tile_bundle_bits -create_SrcBDest_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 20); -} - -static __inline tile_bundle_bits -create_SrcB_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tile_bundle_bits -create_SrcB_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tile_bundle_bits -create_SrcB_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tile_bundle_bits -create_SrcB_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tile_bundle_bits -create_Src_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 0); -} - -static __inline tile_bundle_bits -create_UnOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 12); -} - -static __inline tile_bundle_bits -create_UnOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1f)) << 43); -} - -static __inline tile_bundle_bits -create_UnOpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 12); -} - -static __inline tile_bundle_bits -create_UnOpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x1f)) << 43); -} - -static __inline tile_bundle_bits -create_UnShOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 17); -} - -static __inline tile_bundle_bits -create_UnShOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x3ff)) << 48); -} - -static __inline tile_bundle_bits -create_UnShOpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x7) << 17); -} - -static __inline tile_bundle_bits -create_UnShOpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tile_bundle_bits)(n & 0x7)) << 48); -} - - - -typedef enum -{ - TILE_PIPELINE_X0, - TILE_PIPELINE_X1, - TILE_PIPELINE_Y0, - TILE_PIPELINE_Y1, - TILE_PIPELINE_Y2, -} tile_pipeline; - -#define tile_is_x_pipeline(p) ((int)(p) <= (int)TILE_PIPELINE_X1) - -typedef enum -{ - TILE_OP_TYPE_REGISTER, - TILE_OP_TYPE_IMMEDIATE, - TILE_OP_TYPE_ADDRESS, - TILE_OP_TYPE_SPR -} tile_operand_type; - -/* This is the bit that determines if a bundle is in the Y encoding. */ -#define TILE_BUNDLE_Y_ENCODING_MASK ((tile_bundle_bits)1 << 63) - -enum -{ - /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */ - TILE_MAX_INSTRUCTIONS_PER_BUNDLE = 3, - - /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */ - TILE_NUM_PIPELINE_ENCODINGS = 5, - - /* Log base 2 of TILE_BUNDLE_SIZE_IN_BYTES. */ - TILE_LOG2_BUNDLE_SIZE_IN_BYTES = 3, - - /* Instructions take this many bytes. */ - TILE_BUNDLE_SIZE_IN_BYTES = 1 << TILE_LOG2_BUNDLE_SIZE_IN_BYTES, - - /* Log base 2 of TILE_BUNDLE_ALIGNMENT_IN_BYTES. */ - TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3, - - /* Bundles should be aligned modulo this number of bytes. */ - TILE_BUNDLE_ALIGNMENT_IN_BYTES = - (1 << TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES), - - /* Log base 2 of TILE_SN_INSTRUCTION_SIZE_IN_BYTES. */ - TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES = 1, - - /* Static network instructions take this many bytes. */ - TILE_SN_INSTRUCTION_SIZE_IN_BYTES = - (1 << TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES), - - /* Number of registers (some are magic, such as network I/O). */ - TILE_NUM_REGISTERS = 64, - - /* Number of static network registers. */ - TILE_NUM_SN_REGISTERS = 4 -}; - - -struct tile_operand -{ - /* Is this operand a register, immediate or address? */ - tile_operand_type type; - - /* The default relocation type for this operand. */ - signed int default_reloc : 16; - - /* How many bits is this value? (used for range checking) */ - unsigned int num_bits : 5; - - /* Is the value signed? (used for range checking) */ - unsigned int is_signed : 1; - - /* Is this operand a source register? */ - unsigned int is_src_reg : 1; - - /* Is this operand written? (i.e. is it a destination register) */ - unsigned int is_dest_reg : 1; - - /* Is this operand PC-relative? */ - unsigned int is_pc_relative : 1; - - /* By how many bits do we right shift the value before inserting? */ - unsigned int rightshift : 2; - - /* Return the bits for this operand to be ORed into an existing bundle. */ - tile_bundle_bits (*insert) (int op); - - /* Extract this operand and return it. */ - unsigned int (*extract) (tile_bundle_bits bundle); -}; - - -extern const struct tile_operand tile_operands[]; - -/* One finite-state machine per pipe for rapid instruction decoding. */ -extern const unsigned short * const -tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS]; - - -struct tile_opcode -{ - /* The opcode mnemonic, e.g. "add" */ - const char *name; - - /* The enum value for this mnemonic. */ - tile_mnemonic mnemonic; - - /* A bit mask of which of the five pipes this instruction - is compatible with: - X0 0x01 - X1 0x02 - Y0 0x04 - Y1 0x08 - Y2 0x10 */ - unsigned char pipes; - - /* How many operands are there? */ - unsigned char num_operands; - - /* Which register does this write implicitly, or TREG_ZERO if none? */ - unsigned char implicitly_written_register; - - /* Can this be bundled with other instructions (almost always true). */ - unsigned char can_bundle; - - /* The description of the operands. Each of these is an - * index into the tile_operands[] table. */ - unsigned char operands[TILE_NUM_PIPELINE_ENCODINGS][TILE_MAX_OPERANDS]; - -}; - -extern const struct tile_opcode tile_opcodes[]; - - -/* Used for non-textual disassembly into structs. */ -struct tile_decoded_instruction -{ - const struct tile_opcode *opcode; - const struct tile_operand *operands[TILE_MAX_OPERANDS]; - int operand_values[TILE_MAX_OPERANDS]; -}; - - -/* Disassemble a bundle into a struct for machine processing. */ -extern int parse_insn_tile(tile_bundle_bits bits, - unsigned int pc, - struct tile_decoded_instruction - decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]); - - -/* Given a set of bundle bits and a specific pipe, returns which - * instruction the bundle contains in that pipe. - */ -extern const struct tile_opcode * -find_opcode(tile_bundle_bits bits, tile_pipeline pipe); - - - -#endif /* opcode_tile_h */ diff --git a/arch/tile/include/asm/opcode-tile_64.h b/arch/tile/include/asm/opcode-tile_64.h deleted file mode 100644 index c0633466cd5c..000000000000 --- a/arch/tile/include/asm/opcode-tile_64.h +++ /dev/null @@ -1,1248 +0,0 @@ -/* tile.h -- Header file for TILE opcode table - Copyright (C) 2005 Free Software Foundation, Inc. - Contributed by Tilera Corp. */ - -#ifndef opcode_tile_h -#define opcode_tile_h - -typedef unsigned long long tilegx_bundle_bits; - - -enum -{ - TILEGX_MAX_OPERANDS = 4 /* bfexts */ -}; - -typedef enum -{ - TILEGX_OPC_BPT, - TILEGX_OPC_INFO, - TILEGX_OPC_INFOL, - TILEGX_OPC_MOVE, - TILEGX_OPC_MOVEI, - TILEGX_OPC_MOVELI, - TILEGX_OPC_PREFETCH, - TILEGX_OPC_PREFETCH_ADD_L1, - TILEGX_OPC_PREFETCH_ADD_L1_FAULT, - TILEGX_OPC_PREFETCH_ADD_L2, - TILEGX_OPC_PREFETCH_ADD_L2_FAULT, - TILEGX_OPC_PREFETCH_ADD_L3, - TILEGX_OPC_PREFETCH_ADD_L3_FAULT, - TILEGX_OPC_PREFETCH_L1, - TILEGX_OPC_PREFETCH_L1_FAULT, - TILEGX_OPC_PREFETCH_L2, - TILEGX_OPC_PREFETCH_L2_FAULT, - TILEGX_OPC_PREFETCH_L3, - TILEGX_OPC_PREFETCH_L3_FAULT, - TILEGX_OPC_RAISE, - TILEGX_OPC_ADD, - TILEGX_OPC_ADDI, - TILEGX_OPC_ADDLI, - TILEGX_OPC_ADDX, - TILEGX_OPC_ADDXI, - TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXSC, - TILEGX_OPC_AND, - TILEGX_OPC_ANDI, - TILEGX_OPC_BEQZ, - TILEGX_OPC_BEQZT, - TILEGX_OPC_BFEXTS, - TILEGX_OPC_BFEXTU, - TILEGX_OPC_BFINS, - TILEGX_OPC_BGEZ, - TILEGX_OPC_BGEZT, - TILEGX_OPC_BGTZ, - TILEGX_OPC_BGTZT, - TILEGX_OPC_BLBC, - TILEGX_OPC_BLBCT, - TILEGX_OPC_BLBS, - TILEGX_OPC_BLBST, - TILEGX_OPC_BLEZ, - TILEGX_OPC_BLEZT, - TILEGX_OPC_BLTZ, - TILEGX_OPC_BLTZT, - TILEGX_OPC_BNEZ, - TILEGX_OPC_BNEZT, - TILEGX_OPC_CLZ, - TILEGX_OPC_CMOVEQZ, - TILEGX_OPC_CMOVNEZ, - TILEGX_OPC_CMPEQ, - TILEGX_OPC_CMPEQI, - TILEGX_OPC_CMPEXCH, - TILEGX_OPC_CMPEXCH4, - TILEGX_OPC_CMPLES, - TILEGX_OPC_CMPLEU, - TILEGX_OPC_CMPLTS, - TILEGX_OPC_CMPLTSI, - TILEGX_OPC_CMPLTU, - TILEGX_OPC_CMPLTUI, - TILEGX_OPC_CMPNE, - TILEGX_OPC_CMUL, - TILEGX_OPC_CMULA, - TILEGX_OPC_CMULAF, - TILEGX_OPC_CMULF, - TILEGX_OPC_CMULFR, - TILEGX_OPC_CMULH, - TILEGX_OPC_CMULHR, - TILEGX_OPC_CRC32_32, - TILEGX_OPC_CRC32_8, - TILEGX_OPC_CTZ, - TILEGX_OPC_DBLALIGN, - TILEGX_OPC_DBLALIGN2, - TILEGX_OPC_DBLALIGN4, - TILEGX_OPC_DBLALIGN6, - TILEGX_OPC_DRAIN, - TILEGX_OPC_DTLBPR, - TILEGX_OPC_EXCH, - TILEGX_OPC_EXCH4, - TILEGX_OPC_FDOUBLE_ADD_FLAGS, - TILEGX_OPC_FDOUBLE_ADDSUB, - TILEGX_OPC_FDOUBLE_MUL_FLAGS, - TILEGX_OPC_FDOUBLE_PACK1, - TILEGX_OPC_FDOUBLE_PACK2, - TILEGX_OPC_FDOUBLE_SUB_FLAGS, - TILEGX_OPC_FDOUBLE_UNPACK_MAX, - TILEGX_OPC_FDOUBLE_UNPACK_MIN, - TILEGX_OPC_FETCHADD, - TILEGX_OPC_FETCHADD4, - TILEGX_OPC_FETCHADDGEZ, - TILEGX_OPC_FETCHADDGEZ4, - TILEGX_OPC_FETCHAND, - TILEGX_OPC_FETCHAND4, - TILEGX_OPC_FETCHOR, - TILEGX_OPC_FETCHOR4, - TILEGX_OPC_FINV, - TILEGX_OPC_FLUSH, - TILEGX_OPC_FLUSHWB, - TILEGX_OPC_FNOP, - TILEGX_OPC_FSINGLE_ADD1, - TILEGX_OPC_FSINGLE_ADDSUB2, - TILEGX_OPC_FSINGLE_MUL1, - TILEGX_OPC_FSINGLE_MUL2, - TILEGX_OPC_FSINGLE_PACK1, - TILEGX_OPC_FSINGLE_PACK2, - TILEGX_OPC_FSINGLE_SUB1, - TILEGX_OPC_ICOH, - TILEGX_OPC_ILL, - TILEGX_OPC_INV, - TILEGX_OPC_IRET, - TILEGX_OPC_J, - TILEGX_OPC_JAL, - TILEGX_OPC_JALR, - TILEGX_OPC_JALRP, - TILEGX_OPC_JR, - TILEGX_OPC_JRP, - TILEGX_OPC_LD, - TILEGX_OPC_LD1S, - TILEGX_OPC_LD1S_ADD, - TILEGX_OPC_LD1U, - TILEGX_OPC_LD1U_ADD, - TILEGX_OPC_LD2S, - TILEGX_OPC_LD2S_ADD, - TILEGX_OPC_LD2U, - TILEGX_OPC_LD2U_ADD, - TILEGX_OPC_LD4S, - TILEGX_OPC_LD4S_ADD, - TILEGX_OPC_LD4U, - TILEGX_OPC_LD4U_ADD, - TILEGX_OPC_LD_ADD, - TILEGX_OPC_LDNA, - TILEGX_OPC_LDNA_ADD, - TILEGX_OPC_LDNT, - TILEGX_OPC_LDNT1S, - TILEGX_OPC_LDNT1S_ADD, - TILEGX_OPC_LDNT1U, - TILEGX_OPC_LDNT1U_ADD, - TILEGX_OPC_LDNT2S, - TILEGX_OPC_LDNT2S_ADD, - TILEGX_OPC_LDNT2U, - TILEGX_OPC_LDNT2U_ADD, - TILEGX_OPC_LDNT4S, - TILEGX_OPC_LDNT4S_ADD, - TILEGX_OPC_LDNT4U, - TILEGX_OPC_LDNT4U_ADD, - TILEGX_OPC_LDNT_ADD, - TILEGX_OPC_LNK, - TILEGX_OPC_MF, - TILEGX_OPC_MFSPR, - TILEGX_OPC_MM, - TILEGX_OPC_MNZ, - TILEGX_OPC_MTSPR, - TILEGX_OPC_MUL_HS_HS, - TILEGX_OPC_MUL_HS_HU, - TILEGX_OPC_MUL_HS_LS, - TILEGX_OPC_MUL_HS_LU, - TILEGX_OPC_MUL_HU_HU, - TILEGX_OPC_MUL_HU_LS, - TILEGX_OPC_MUL_HU_LU, - TILEGX_OPC_MUL_LS_LS, - TILEGX_OPC_MUL_LS_LU, - TILEGX_OPC_MUL_LU_LU, - TILEGX_OPC_MULA_HS_HS, - TILEGX_OPC_MULA_HS_HU, - TILEGX_OPC_MULA_HS_LS, - TILEGX_OPC_MULA_HS_LU, - TILEGX_OPC_MULA_HU_HU, - TILEGX_OPC_MULA_HU_LS, - TILEGX_OPC_MULA_HU_LU, - TILEGX_OPC_MULA_LS_LS, - TILEGX_OPC_MULA_LS_LU, - TILEGX_OPC_MULA_LU_LU, - TILEGX_OPC_MULAX, - TILEGX_OPC_MULX, - TILEGX_OPC_MZ, - TILEGX_OPC_NAP, - TILEGX_OPC_NOP, - TILEGX_OPC_NOR, - TILEGX_OPC_OR, - TILEGX_OPC_ORI, - TILEGX_OPC_PCNT, - TILEGX_OPC_REVBITS, - TILEGX_OPC_REVBYTES, - TILEGX_OPC_ROTL, - TILEGX_OPC_ROTLI, - TILEGX_OPC_SHL, - TILEGX_OPC_SHL16INSLI, - TILEGX_OPC_SHL1ADD, - TILEGX_OPC_SHL1ADDX, - TILEGX_OPC_SHL2ADD, - TILEGX_OPC_SHL2ADDX, - TILEGX_OPC_SHL3ADD, - TILEGX_OPC_SHL3ADDX, - TILEGX_OPC_SHLI, - TILEGX_OPC_SHLX, - TILEGX_OPC_SHLXI, - TILEGX_OPC_SHRS, - TILEGX_OPC_SHRSI, - TILEGX_OPC_SHRU, - TILEGX_OPC_SHRUI, - TILEGX_OPC_SHRUX, - TILEGX_OPC_SHRUXI, - TILEGX_OPC_SHUFFLEBYTES, - TILEGX_OPC_ST, - TILEGX_OPC_ST1, - TILEGX_OPC_ST1_ADD, - TILEGX_OPC_ST2, - TILEGX_OPC_ST2_ADD, - TILEGX_OPC_ST4, - TILEGX_OPC_ST4_ADD, - TILEGX_OPC_ST_ADD, - TILEGX_OPC_STNT, - TILEGX_OPC_STNT1, - TILEGX_OPC_STNT1_ADD, - TILEGX_OPC_STNT2, - TILEGX_OPC_STNT2_ADD, - TILEGX_OPC_STNT4, - TILEGX_OPC_STNT4_ADD, - TILEGX_OPC_STNT_ADD, - TILEGX_OPC_SUB, - TILEGX_OPC_SUBX, - TILEGX_OPC_SUBXSC, - TILEGX_OPC_SWINT0, - TILEGX_OPC_SWINT1, - TILEGX_OPC_SWINT2, - TILEGX_OPC_SWINT3, - TILEGX_OPC_TBLIDXB0, - TILEGX_OPC_TBLIDXB1, - TILEGX_OPC_TBLIDXB2, - TILEGX_OPC_TBLIDXB3, - TILEGX_OPC_V1ADD, - TILEGX_OPC_V1ADDI, - TILEGX_OPC_V1ADDUC, - TILEGX_OPC_V1ADIFFU, - TILEGX_OPC_V1AVGU, - TILEGX_OPC_V1CMPEQ, - TILEGX_OPC_V1CMPEQI, - TILEGX_OPC_V1CMPLES, - TILEGX_OPC_V1CMPLEU, - TILEGX_OPC_V1CMPLTS, - TILEGX_OPC_V1CMPLTSI, - TILEGX_OPC_V1CMPLTU, - TILEGX_OPC_V1CMPLTUI, - TILEGX_OPC_V1CMPNE, - TILEGX_OPC_V1DDOTPU, - TILEGX_OPC_V1DDOTPUA, - TILEGX_OPC_V1DDOTPUS, - TILEGX_OPC_V1DDOTPUSA, - TILEGX_OPC_V1DOTP, - TILEGX_OPC_V1DOTPA, - TILEGX_OPC_V1DOTPU, - TILEGX_OPC_V1DOTPUA, - TILEGX_OPC_V1DOTPUS, - TILEGX_OPC_V1DOTPUSA, - TILEGX_OPC_V1INT_H, - TILEGX_OPC_V1INT_L, - TILEGX_OPC_V1MAXU, - TILEGX_OPC_V1MAXUI, - TILEGX_OPC_V1MINU, - TILEGX_OPC_V1MINUI, - TILEGX_OPC_V1MNZ, - TILEGX_OPC_V1MULTU, - TILEGX_OPC_V1MULU, - TILEGX_OPC_V1MULUS, - TILEGX_OPC_V1MZ, - TILEGX_OPC_V1SADAU, - TILEGX_OPC_V1SADU, - TILEGX_OPC_V1SHL, - TILEGX_OPC_V1SHLI, - TILEGX_OPC_V1SHRS, - TILEGX_OPC_V1SHRSI, - TILEGX_OPC_V1SHRU, - TILEGX_OPC_V1SHRUI, - TILEGX_OPC_V1SUB, - TILEGX_OPC_V1SUBUC, - TILEGX_OPC_V2ADD, - TILEGX_OPC_V2ADDI, - TILEGX_OPC_V2ADDSC, - TILEGX_OPC_V2ADIFFS, - TILEGX_OPC_V2AVGS, - TILEGX_OPC_V2CMPEQ, - TILEGX_OPC_V2CMPEQI, - TILEGX_OPC_V2CMPLES, - TILEGX_OPC_V2CMPLEU, - TILEGX_OPC_V2CMPLTS, - TILEGX_OPC_V2CMPLTSI, - TILEGX_OPC_V2CMPLTU, - TILEGX_OPC_V2CMPLTUI, - TILEGX_OPC_V2CMPNE, - TILEGX_OPC_V2DOTP, - TILEGX_OPC_V2DOTPA, - TILEGX_OPC_V2INT_H, - TILEGX_OPC_V2INT_L, - TILEGX_OPC_V2MAXS, - TILEGX_OPC_V2MAXSI, - TILEGX_OPC_V2MINS, - TILEGX_OPC_V2MINSI, - TILEGX_OPC_V2MNZ, - TILEGX_OPC_V2MULFSC, - TILEGX_OPC_V2MULS, - TILEGX_OPC_V2MULTS, - TILEGX_OPC_V2MZ, - TILEGX_OPC_V2PACKH, - TILEGX_OPC_V2PACKL, - TILEGX_OPC_V2PACKUC, - TILEGX_OPC_V2SADAS, - TILEGX_OPC_V2SADAU, - TILEGX_OPC_V2SADS, - TILEGX_OPC_V2SADU, - TILEGX_OPC_V2SHL, - TILEGX_OPC_V2SHLI, - TILEGX_OPC_V2SHLSC, - TILEGX_OPC_V2SHRS, - TILEGX_OPC_V2SHRSI, - TILEGX_OPC_V2SHRU, - TILEGX_OPC_V2SHRUI, - TILEGX_OPC_V2SUB, - TILEGX_OPC_V2SUBSC, - TILEGX_OPC_V4ADD, - TILEGX_OPC_V4ADDSC, - TILEGX_OPC_V4INT_H, - TILEGX_OPC_V4INT_L, - TILEGX_OPC_V4PACKSC, - TILEGX_OPC_V4SHL, - TILEGX_OPC_V4SHLSC, - TILEGX_OPC_V4SHRS, - TILEGX_OPC_V4SHRU, - TILEGX_OPC_V4SUB, - TILEGX_OPC_V4SUBSC, - TILEGX_OPC_WH64, - TILEGX_OPC_XOR, - TILEGX_OPC_XORI, - TILEGX_OPC_NONE -} tilegx_mnemonic; - -/* 64-bit pattern for a { bpt ; nop } bundle. */ -#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL - - -#define TILE_ELF_MACHINE_CODE EM_TILE64 - -#define TILE_ELF_NAME "elf32-tile64" - - -static __inline unsigned int -get_BFEnd_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_BFOpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 24)) & 0xf); -} - -static __inline unsigned int -get_BFStart_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3f); -} - -static __inline unsigned int -get_BrOff_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 37)) & 0x0001ffc0); -} - -static __inline unsigned int -get_BrType_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 54)) & 0x1f); -} - -static __inline unsigned int -get_Dest_Imm8_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 43)) & 0x000000c0); -} - -static __inline unsigned int -get_Dest_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3f); -} - -static __inline unsigned int -get_Dest_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x3f); -} - -static __inline unsigned int -get_Dest_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3f); -} - -static __inline unsigned int -get_Dest_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x3f); -} - -static __inline unsigned int -get_Imm16_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xffff); -} - -static __inline unsigned int -get_Imm16_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xffff); -} - -static __inline unsigned int -get_Imm8OpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 20)) & 0xff); -} - -static __inline unsigned int -get_Imm8OpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 51)) & 0xff); -} - -static __inline unsigned int -get_Imm8_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xff); -} - -static __inline unsigned int -get_Imm8_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xff); -} - -static __inline unsigned int -get_Imm8_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xff); -} - -static __inline unsigned int -get_Imm8_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xff); -} - -static __inline unsigned int -get_JumpOff_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x7ffffff); -} - -static __inline unsigned int -get_JumpOpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 58)) & 0x1); -} - -static __inline unsigned int -get_MF_Imm14_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3fff); -} - -static __inline unsigned int -get_MT_Imm14_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 37)) & 0x00003fc0); -} - -static __inline unsigned int -get_Mode(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 62)) & 0x3); -} - -static __inline unsigned int -get_Opcode_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 28)) & 0x7); -} - -static __inline unsigned int -get_Opcode_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 59)) & 0x7); -} - -static __inline unsigned int -get_Opcode_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 27)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 58)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y2(tilegx_bundle_bits n) -{ - return (((n >> 26)) & 0x00000001) | - (((unsigned int)(n >> 56)) & 0x00000002); -} - -static __inline unsigned int -get_RRROpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3ff); -} - -static __inline unsigned int -get_RRROpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3ff); -} - -static __inline unsigned int -get_RRROpcodeExtension_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3); -} - -static __inline unsigned int -get_RRROpcodeExtension_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3); -} - -static __inline unsigned int -get_ShAmt_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_ShAmt_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_ShAmt_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_ShAmt_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_ShiftOpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3ff); -} - -static __inline unsigned int -get_ShiftOpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3ff); -} - -static __inline unsigned int -get_ShiftOpcodeExtension_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3); -} - -static __inline unsigned int -get_ShiftOpcodeExtension_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3); -} - -static __inline unsigned int -get_SrcA_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 6)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 6)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y2(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 20)) & 0x3f); -} - -static __inline unsigned int -get_SrcBDest_Y2(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 51)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_UnaryOpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_UnaryOpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_UnaryOpcodeExtension_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_UnaryOpcodeExtension_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - - -static __inline int -sign_extend(int n, int num_bits) -{ - int shift = (int)(sizeof(int) * 8 - num_bits); - return (n << shift) >> shift; -} - - - -static __inline tilegx_bundle_bits -create_BFEnd_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_BFOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 24); -} - -static __inline tilegx_bundle_bits -create_BFStart_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 18); -} - -static __inline tilegx_bundle_bits -create_BrOff_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | - (((tilegx_bundle_bits)(n & 0x0001ffc0)) << 37); -} - -static __inline tilegx_bundle_bits -create_BrType_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x1f)) << 54); -} - -static __inline tilegx_bundle_bits -create_Dest_Imm8_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | - (((tilegx_bundle_bits)(n & 0x000000c0)) << 43); -} - -static __inline tilegx_bundle_bits -create_Dest_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 0); -} - -static __inline tilegx_bundle_bits -create_Dest_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 31); -} - -static __inline tilegx_bundle_bits -create_Dest_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 0); -} - -static __inline tilegx_bundle_bits -create_Dest_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 31); -} - -static __inline tilegx_bundle_bits -create_Imm16_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xffff) << 12); -} - -static __inline tilegx_bundle_bits -create_Imm16_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xffff)) << 43); -} - -static __inline tilegx_bundle_bits -create_Imm8OpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 20); -} - -static __inline tilegx_bundle_bits -create_Imm8OpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xff)) << 51); -} - -static __inline tilegx_bundle_bits -create_Imm8_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 12); -} - -static __inline tilegx_bundle_bits -create_Imm8_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xff)) << 43); -} - -static __inline tilegx_bundle_bits -create_Imm8_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 12); -} - -static __inline tilegx_bundle_bits -create_Imm8_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xff)) << 43); -} - -static __inline tilegx_bundle_bits -create_JumpOff_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x7ffffff)) << 31); -} - -static __inline tilegx_bundle_bits -create_JumpOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x1)) << 58); -} - -static __inline tilegx_bundle_bits -create_MF_Imm14_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3fff)) << 37); -} - -static __inline tilegx_bundle_bits -create_MT_Imm14_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | - (((tilegx_bundle_bits)(n & 0x00003fc0)) << 37); -} - -static __inline tilegx_bundle_bits -create_Mode(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3)) << 62); -} - -static __inline tilegx_bundle_bits -create_Opcode_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x7) << 28); -} - -static __inline tilegx_bundle_bits -create_Opcode_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x7)) << 59); -} - -static __inline tilegx_bundle_bits -create_Opcode_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 27); -} - -static __inline tilegx_bundle_bits -create_Opcode_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xf)) << 58); -} - -static __inline tilegx_bundle_bits -create_Opcode_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x00000001) << 26) | - (((tilegx_bundle_bits)(n & 0x00000002)) << 56); -} - -static __inline tilegx_bundle_bits -create_RRROpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 18); -} - -static __inline tilegx_bundle_bits -create_RRROpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3ff)) << 49); -} - -static __inline tilegx_bundle_bits -create_RRROpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 18); -} - -static __inline tilegx_bundle_bits -create_RRROpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3)) << 49); -} - -static __inline tilegx_bundle_bits -create_ShAmt_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_ShAmt_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_ShAmt_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_ShAmt_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_ShiftOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 18); -} - -static __inline tilegx_bundle_bits -create_ShiftOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3ff)) << 49); -} - -static __inline tilegx_bundle_bits -create_ShiftOpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 18); -} - -static __inline tilegx_bundle_bits -create_ShiftOpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3)) << 49); -} - -static __inline tilegx_bundle_bits -create_SrcA_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 6); -} - -static __inline tilegx_bundle_bits -create_SrcA_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 37); -} - -static __inline tilegx_bundle_bits -create_SrcA_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 6); -} - -static __inline tilegx_bundle_bits -create_SrcA_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 37); -} - -static __inline tilegx_bundle_bits -create_SrcA_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 20); -} - -static __inline tilegx_bundle_bits -create_SrcBDest_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 51); -} - -static __inline tilegx_bundle_bits -create_SrcB_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_SrcB_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_SrcB_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_SrcB_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_UnaryOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_UnaryOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_UnaryOpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_UnaryOpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - - -typedef enum -{ - TILEGX_PIPELINE_X0, - TILEGX_PIPELINE_X1, - TILEGX_PIPELINE_Y0, - TILEGX_PIPELINE_Y1, - TILEGX_PIPELINE_Y2, -} tilegx_pipeline; - -#define tilegx_is_x_pipeline(p) ((int)(p) <= (int)TILEGX_PIPELINE_X1) - -typedef enum -{ - TILEGX_OP_TYPE_REGISTER, - TILEGX_OP_TYPE_IMMEDIATE, - TILEGX_OP_TYPE_ADDRESS, - TILEGX_OP_TYPE_SPR -} tilegx_operand_type; - -/* These are the bits that determine if a bundle is in the X encoding. */ -#define TILEGX_BUNDLE_MODE_MASK ((tilegx_bundle_bits)3 << 62) - -enum -{ - /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */ - TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE = 3, - - /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */ - TILEGX_NUM_PIPELINE_ENCODINGS = 5, - - /* Log base 2 of TILEGX_BUNDLE_SIZE_IN_BYTES. */ - TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES = 3, - - /* Instructions take this many bytes. */ - TILEGX_BUNDLE_SIZE_IN_BYTES = 1 << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES, - - /* Log base 2 of TILEGX_BUNDLE_ALIGNMENT_IN_BYTES. */ - TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3, - - /* Bundles should be aligned modulo this number of bytes. */ - TILEGX_BUNDLE_ALIGNMENT_IN_BYTES = - (1 << TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES), - - /* Number of registers (some are magic, such as network I/O). */ - TILEGX_NUM_REGISTERS = 64, -}; - - -struct tilegx_operand -{ - /* Is this operand a register, immediate or address? */ - tilegx_operand_type type; - - /* The default relocation type for this operand. */ - signed int default_reloc : 16; - - /* How many bits is this value? (used for range checking) */ - unsigned int num_bits : 5; - - /* Is the value signed? (used for range checking) */ - unsigned int is_signed : 1; - - /* Is this operand a source register? */ - unsigned int is_src_reg : 1; - - /* Is this operand written? (i.e. is it a destination register) */ - unsigned int is_dest_reg : 1; - - /* Is this operand PC-relative? */ - unsigned int is_pc_relative : 1; - - /* By how many bits do we right shift the value before inserting? */ - unsigned int rightshift : 2; - - /* Return the bits for this operand to be ORed into an existing bundle. */ - tilegx_bundle_bits (*insert) (int op); - - /* Extract this operand and return it. */ - unsigned int (*extract) (tilegx_bundle_bits bundle); -}; - - -extern const struct tilegx_operand tilegx_operands[]; - -/* One finite-state machine per pipe for rapid instruction decoding. */ -extern const unsigned short * const -tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS]; - - -struct tilegx_opcode -{ - /* The opcode mnemonic, e.g. "add" */ - const char *name; - - /* The enum value for this mnemonic. */ - tilegx_mnemonic mnemonic; - - /* A bit mask of which of the five pipes this instruction - is compatible with: - X0 0x01 - X1 0x02 - Y0 0x04 - Y1 0x08 - Y2 0x10 */ - unsigned char pipes; - - /* How many operands are there? */ - unsigned char num_operands; - - /* Which register does this write implicitly, or TREG_ZERO if none? */ - unsigned char implicitly_written_register; - - /* Can this be bundled with other instructions (almost always true). */ - unsigned char can_bundle; - - /* The description of the operands. Each of these is an - * index into the tilegx_operands[] table. */ - unsigned char operands[TILEGX_NUM_PIPELINE_ENCODINGS][TILEGX_MAX_OPERANDS]; - -}; - -extern const struct tilegx_opcode tilegx_opcodes[]; - -/* Used for non-textual disassembly into structs. */ -struct tilegx_decoded_instruction -{ - const struct tilegx_opcode *opcode; - const struct tilegx_operand *operands[TILEGX_MAX_OPERANDS]; - long long operand_values[TILEGX_MAX_OPERANDS]; -}; - - -/* Disassemble a bundle into a struct for machine processing. */ -extern int parse_insn_tilegx(tilegx_bundle_bits bits, - unsigned long long pc, - struct tilegx_decoded_instruction - decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]); - - - -#endif /* opcode_tilegx_h */ diff --git a/arch/tile/include/asm/opcode_constants_32.h b/arch/tile/include/asm/opcode_constants_32.h deleted file mode 100644 index 227d033b180c..000000000000 --- a/arch/tile/include/asm/opcode_constants_32.h +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ - - -#ifndef _TILE_OPCODE_CONSTANTS_H -#define _TILE_OPCODE_CONSTANTS_H -enum -{ - ADDBS_U_SPECIAL_0_OPCODE_X0 = 98, - ADDBS_U_SPECIAL_0_OPCODE_X1 = 68, - ADDB_SPECIAL_0_OPCODE_X0 = 1, - ADDB_SPECIAL_0_OPCODE_X1 = 1, - ADDHS_SPECIAL_0_OPCODE_X0 = 99, - ADDHS_SPECIAL_0_OPCODE_X1 = 69, - ADDH_SPECIAL_0_OPCODE_X0 = 2, - ADDH_SPECIAL_0_OPCODE_X1 = 2, - ADDIB_IMM_0_OPCODE_X0 = 1, - ADDIB_IMM_0_OPCODE_X1 = 1, - ADDIH_IMM_0_OPCODE_X0 = 2, - ADDIH_IMM_0_OPCODE_X1 = 2, - ADDI_IMM_0_OPCODE_X0 = 3, - ADDI_IMM_0_OPCODE_X1 = 3, - ADDI_IMM_1_OPCODE_SN = 1, - ADDI_OPCODE_Y0 = 9, - ADDI_OPCODE_Y1 = 7, - ADDLIS_OPCODE_X0 = 1, - ADDLIS_OPCODE_X1 = 2, - ADDLI_OPCODE_X0 = 2, - ADDLI_OPCODE_X1 = 3, - ADDS_SPECIAL_0_OPCODE_X0 = 96, - ADDS_SPECIAL_0_OPCODE_X1 = 66, - ADD_SPECIAL_0_OPCODE_X0 = 3, - ADD_SPECIAL_0_OPCODE_X1 = 3, - ADD_SPECIAL_0_OPCODE_Y0 = 0, - ADD_SPECIAL_0_OPCODE_Y1 = 0, - ADIFFB_U_SPECIAL_0_OPCODE_X0 = 4, - ADIFFH_SPECIAL_0_OPCODE_X0 = 5, - ANDI_IMM_0_OPCODE_X0 = 1, - ANDI_IMM_0_OPCODE_X1 = 4, - ANDI_OPCODE_Y0 = 10, - ANDI_OPCODE_Y1 = 8, - AND_SPECIAL_0_OPCODE_X0 = 6, - AND_SPECIAL_0_OPCODE_X1 = 4, - AND_SPECIAL_2_OPCODE_Y0 = 0, - AND_SPECIAL_2_OPCODE_Y1 = 0, - AULI_OPCODE_X0 = 3, - AULI_OPCODE_X1 = 4, - AVGB_U_SPECIAL_0_OPCODE_X0 = 7, - AVGH_SPECIAL_0_OPCODE_X0 = 8, - BBNST_BRANCH_OPCODE_X1 = 15, - BBNS_BRANCH_OPCODE_X1 = 14, - BBNS_OPCODE_SN = 63, - BBST_BRANCH_OPCODE_X1 = 13, - BBS_BRANCH_OPCODE_X1 = 12, - BBS_OPCODE_SN = 62, - BGEZT_BRANCH_OPCODE_X1 = 7, - BGEZ_BRANCH_OPCODE_X1 = 6, - BGEZ_OPCODE_SN = 61, - BGZT_BRANCH_OPCODE_X1 = 5, - BGZ_BRANCH_OPCODE_X1 = 4, - BGZ_OPCODE_SN = 58, - BITX_UN_0_SHUN_0_OPCODE_X0 = 1, - BITX_UN_0_SHUN_0_OPCODE_Y0 = 1, - BLEZT_BRANCH_OPCODE_X1 = 11, - BLEZ_BRANCH_OPCODE_X1 = 10, - BLEZ_OPCODE_SN = 59, - BLZT_BRANCH_OPCODE_X1 = 9, - BLZ_BRANCH_OPCODE_X1 = 8, - BLZ_OPCODE_SN = 60, - BNZT_BRANCH_OPCODE_X1 = 3, - BNZ_BRANCH_OPCODE_X1 = 2, - BNZ_OPCODE_SN = 57, - BPT_NOREG_RR_IMM_0_OPCODE_SN = 1, - BRANCH_OPCODE_X1 = 5, - BYTEX_UN_0_SHUN_0_OPCODE_X0 = 2, - BYTEX_UN_0_SHUN_0_OPCODE_Y0 = 2, - BZT_BRANCH_OPCODE_X1 = 1, - BZ_BRANCH_OPCODE_X1 = 0, - BZ_OPCODE_SN = 56, - CLZ_UN_0_SHUN_0_OPCODE_X0 = 3, - CLZ_UN_0_SHUN_0_OPCODE_Y0 = 3, - CRC32_32_SPECIAL_0_OPCODE_X0 = 9, - CRC32_8_SPECIAL_0_OPCODE_X0 = 10, - CTZ_UN_0_SHUN_0_OPCODE_X0 = 4, - CTZ_UN_0_SHUN_0_OPCODE_Y0 = 4, - DRAIN_UN_0_SHUN_0_OPCODE_X1 = 1, - DTLBPR_UN_0_SHUN_0_OPCODE_X1 = 2, - DWORD_ALIGN_SPECIAL_0_OPCODE_X0 = 95, - FINV_UN_0_SHUN_0_OPCODE_X1 = 3, - FLUSH_UN_0_SHUN_0_OPCODE_X1 = 4, - FNOP_NOREG_RR_IMM_0_OPCODE_SN = 3, - FNOP_UN_0_SHUN_0_OPCODE_X0 = 5, - FNOP_UN_0_SHUN_0_OPCODE_X1 = 5, - FNOP_UN_0_SHUN_0_OPCODE_Y0 = 5, - FNOP_UN_0_SHUN_0_OPCODE_Y1 = 1, - HALT_NOREG_RR_IMM_0_OPCODE_SN = 0, - ICOH_UN_0_SHUN_0_OPCODE_X1 = 6, - ILL_UN_0_SHUN_0_OPCODE_X1 = 7, - ILL_UN_0_SHUN_0_OPCODE_Y1 = 2, - IMM_0_OPCODE_SN = 0, - IMM_0_OPCODE_X0 = 4, - IMM_0_OPCODE_X1 = 6, - IMM_1_OPCODE_SN = 1, - IMM_OPCODE_0_X0 = 5, - INTHB_SPECIAL_0_OPCODE_X0 = 11, - INTHB_SPECIAL_0_OPCODE_X1 = 5, - INTHH_SPECIAL_0_OPCODE_X0 = 12, - INTHH_SPECIAL_0_OPCODE_X1 = 6, - INTLB_SPECIAL_0_OPCODE_X0 = 13, - INTLB_SPECIAL_0_OPCODE_X1 = 7, - INTLH_SPECIAL_0_OPCODE_X0 = 14, - INTLH_SPECIAL_0_OPCODE_X1 = 8, - INV_UN_0_SHUN_0_OPCODE_X1 = 8, - IRET_UN_0_SHUN_0_OPCODE_X1 = 9, - JALB_OPCODE_X1 = 13, - JALF_OPCODE_X1 = 12, - JALRP_SPECIAL_0_OPCODE_X1 = 9, - JALRR_IMM_1_OPCODE_SN = 3, - JALR_RR_IMM_0_OPCODE_SN = 5, - JALR_SPECIAL_0_OPCODE_X1 = 10, - JB_OPCODE_X1 = 11, - JF_OPCODE_X1 = 10, - JRP_SPECIAL_0_OPCODE_X1 = 11, - JRR_IMM_1_OPCODE_SN = 2, - JR_RR_IMM_0_OPCODE_SN = 4, - JR_SPECIAL_0_OPCODE_X1 = 12, - LBADD_IMM_0_OPCODE_X1 = 22, - LBADD_U_IMM_0_OPCODE_X1 = 23, - LB_OPCODE_Y2 = 0, - LB_UN_0_SHUN_0_OPCODE_X1 = 10, - LB_U_OPCODE_Y2 = 1, - LB_U_UN_0_SHUN_0_OPCODE_X1 = 11, - LHADD_IMM_0_OPCODE_X1 = 24, - LHADD_U_IMM_0_OPCODE_X1 = 25, - LH_OPCODE_Y2 = 2, - LH_UN_0_SHUN_0_OPCODE_X1 = 12, - LH_U_OPCODE_Y2 = 3, - LH_U_UN_0_SHUN_0_OPCODE_X1 = 13, - LNK_SPECIAL_0_OPCODE_X1 = 13, - LWADD_IMM_0_OPCODE_X1 = 26, - LWADD_NA_IMM_0_OPCODE_X1 = 27, - LW_NA_UN_0_SHUN_0_OPCODE_X1 = 24, - LW_OPCODE_Y2 = 4, - LW_UN_0_SHUN_0_OPCODE_X1 = 14, - MAXB_U_SPECIAL_0_OPCODE_X0 = 15, - MAXB_U_SPECIAL_0_OPCODE_X1 = 14, - MAXH_SPECIAL_0_OPCODE_X0 = 16, - MAXH_SPECIAL_0_OPCODE_X1 = 15, - MAXIB_U_IMM_0_OPCODE_X0 = 4, - MAXIB_U_IMM_0_OPCODE_X1 = 5, - MAXIH_IMM_0_OPCODE_X0 = 5, - MAXIH_IMM_0_OPCODE_X1 = 6, - MFSPR_IMM_0_OPCODE_X1 = 7, - MF_UN_0_SHUN_0_OPCODE_X1 = 15, - MINB_U_SPECIAL_0_OPCODE_X0 = 17, - MINB_U_SPECIAL_0_OPCODE_X1 = 16, - MINH_SPECIAL_0_OPCODE_X0 = 18, - MINH_SPECIAL_0_OPCODE_X1 = 17, - MINIB_U_IMM_0_OPCODE_X0 = 6, - MINIB_U_IMM_0_OPCODE_X1 = 8, - MINIH_IMM_0_OPCODE_X0 = 7, - MINIH_IMM_0_OPCODE_X1 = 9, - MM_OPCODE_X0 = 6, - MM_OPCODE_X1 = 7, - MNZB_SPECIAL_0_OPCODE_X0 = 19, - MNZB_SPECIAL_0_OPCODE_X1 = 18, - MNZH_SPECIAL_0_OPCODE_X0 = 20, - MNZH_SPECIAL_0_OPCODE_X1 = 19, - MNZ_SPECIAL_0_OPCODE_X0 = 21, - MNZ_SPECIAL_0_OPCODE_X1 = 20, - MNZ_SPECIAL_1_OPCODE_Y0 = 0, - MNZ_SPECIAL_1_OPCODE_Y1 = 1, - MOVEI_IMM_1_OPCODE_SN = 0, - MOVE_RR_IMM_0_OPCODE_SN = 8, - MTSPR_IMM_0_OPCODE_X1 = 10, - MULHHA_SS_SPECIAL_0_OPCODE_X0 = 22, - MULHHA_SS_SPECIAL_7_OPCODE_Y0 = 0, - MULHHA_SU_SPECIAL_0_OPCODE_X0 = 23, - MULHHA_UU_SPECIAL_0_OPCODE_X0 = 24, - MULHHA_UU_SPECIAL_7_OPCODE_Y0 = 1, - MULHHSA_UU_SPECIAL_0_OPCODE_X0 = 25, - MULHH_SS_SPECIAL_0_OPCODE_X0 = 26, - MULHH_SS_SPECIAL_6_OPCODE_Y0 = 0, - MULHH_SU_SPECIAL_0_OPCODE_X0 = 27, - MULHH_UU_SPECIAL_0_OPCODE_X0 = 28, - MULHH_UU_SPECIAL_6_OPCODE_Y0 = 1, - MULHLA_SS_SPECIAL_0_OPCODE_X0 = 29, - MULHLA_SU_SPECIAL_0_OPCODE_X0 = 30, - MULHLA_US_SPECIAL_0_OPCODE_X0 = 31, - MULHLA_UU_SPECIAL_0_OPCODE_X0 = 32, - MULHLSA_UU_SPECIAL_0_OPCODE_X0 = 33, - MULHLSA_UU_SPECIAL_5_OPCODE_Y0 = 0, - MULHL_SS_SPECIAL_0_OPCODE_X0 = 34, - MULHL_SU_SPECIAL_0_OPCODE_X0 = 35, - MULHL_US_SPECIAL_0_OPCODE_X0 = 36, - MULHL_UU_SPECIAL_0_OPCODE_X0 = 37, - MULLLA_SS_SPECIAL_0_OPCODE_X0 = 38, - MULLLA_SS_SPECIAL_7_OPCODE_Y0 = 2, - MULLLA_SU_SPECIAL_0_OPCODE_X0 = 39, - MULLLA_UU_SPECIAL_0_OPCODE_X0 = 40, - MULLLA_UU_SPECIAL_7_OPCODE_Y0 = 3, - MULLLSA_UU_SPECIAL_0_OPCODE_X0 = 41, - MULLL_SS_SPECIAL_0_OPCODE_X0 = 42, - MULLL_SS_SPECIAL_6_OPCODE_Y0 = 2, - MULLL_SU_SPECIAL_0_OPCODE_X0 = 43, - MULLL_UU_SPECIAL_0_OPCODE_X0 = 44, - MULLL_UU_SPECIAL_6_OPCODE_Y0 = 3, - MVNZ_SPECIAL_0_OPCODE_X0 = 45, - MVNZ_SPECIAL_1_OPCODE_Y0 = 1, - MVZ_SPECIAL_0_OPCODE_X0 = 46, - MVZ_SPECIAL_1_OPCODE_Y0 = 2, - MZB_SPECIAL_0_OPCODE_X0 = 47, - MZB_SPECIAL_0_OPCODE_X1 = 21, - MZH_SPECIAL_0_OPCODE_X0 = 48, - MZH_SPECIAL_0_OPCODE_X1 = 22, - MZ_SPECIAL_0_OPCODE_X0 = 49, - MZ_SPECIAL_0_OPCODE_X1 = 23, - MZ_SPECIAL_1_OPCODE_Y0 = 3, - MZ_SPECIAL_1_OPCODE_Y1 = 2, - NAP_UN_0_SHUN_0_OPCODE_X1 = 16, - NOP_NOREG_RR_IMM_0_OPCODE_SN = 2, - NOP_UN_0_SHUN_0_OPCODE_X0 = 6, - NOP_UN_0_SHUN_0_OPCODE_X1 = 17, - NOP_UN_0_SHUN_0_OPCODE_Y0 = 6, - NOP_UN_0_SHUN_0_OPCODE_Y1 = 3, - NOREG_RR_IMM_0_OPCODE_SN = 0, - NOR_SPECIAL_0_OPCODE_X0 = 50, - NOR_SPECIAL_0_OPCODE_X1 = 24, - NOR_SPECIAL_2_OPCODE_Y0 = 1, - NOR_SPECIAL_2_OPCODE_Y1 = 1, - ORI_IMM_0_OPCODE_X0 = 8, - ORI_IMM_0_OPCODE_X1 = 11, - ORI_OPCODE_Y0 = 11, - ORI_OPCODE_Y1 = 9, - OR_SPECIAL_0_OPCODE_X0 = 51, - OR_SPECIAL_0_OPCODE_X1 = 25, - OR_SPECIAL_2_OPCODE_Y0 = 2, - OR_SPECIAL_2_OPCODE_Y1 = 2, - PACKBS_U_SPECIAL_0_OPCODE_X0 = 103, - PACKBS_U_SPECIAL_0_OPCODE_X1 = 73, - PACKHB_SPECIAL_0_OPCODE_X0 = 52, - PACKHB_SPECIAL_0_OPCODE_X1 = 26, - PACKHS_SPECIAL_0_OPCODE_X0 = 102, - PACKHS_SPECIAL_0_OPCODE_X1 = 72, - PACKLB_SPECIAL_0_OPCODE_X0 = 53, - PACKLB_SPECIAL_0_OPCODE_X1 = 27, - PCNT_UN_0_SHUN_0_OPCODE_X0 = 7, - PCNT_UN_0_SHUN_0_OPCODE_Y0 = 7, - RLI_SHUN_0_OPCODE_X0 = 1, - RLI_SHUN_0_OPCODE_X1 = 1, - RLI_SHUN_0_OPCODE_Y0 = 1, - RLI_SHUN_0_OPCODE_Y1 = 1, - RL_SPECIAL_0_OPCODE_X0 = 54, - RL_SPECIAL_0_OPCODE_X1 = 28, - RL_SPECIAL_3_OPCODE_Y0 = 0, - RL_SPECIAL_3_OPCODE_Y1 = 0, - RR_IMM_0_OPCODE_SN = 0, - S1A_SPECIAL_0_OPCODE_X0 = 55, - S1A_SPECIAL_0_OPCODE_X1 = 29, - S1A_SPECIAL_0_OPCODE_Y0 = 1, - S1A_SPECIAL_0_OPCODE_Y1 = 1, - S2A_SPECIAL_0_OPCODE_X0 = 56, - S2A_SPECIAL_0_OPCODE_X1 = 30, - S2A_SPECIAL_0_OPCODE_Y0 = 2, - S2A_SPECIAL_0_OPCODE_Y1 = 2, - S3A_SPECIAL_0_OPCODE_X0 = 57, - S3A_SPECIAL_0_OPCODE_X1 = 31, - S3A_SPECIAL_5_OPCODE_Y0 = 1, - S3A_SPECIAL_5_OPCODE_Y1 = 1, - SADAB_U_SPECIAL_0_OPCODE_X0 = 58, - SADAH_SPECIAL_0_OPCODE_X0 = 59, - SADAH_U_SPECIAL_0_OPCODE_X0 = 60, - SADB_U_SPECIAL_0_OPCODE_X0 = 61, - SADH_SPECIAL_0_OPCODE_X0 = 62, - SADH_U_SPECIAL_0_OPCODE_X0 = 63, - SBADD_IMM_0_OPCODE_X1 = 28, - SB_OPCODE_Y2 = 5, - SB_SPECIAL_0_OPCODE_X1 = 32, - SEQB_SPECIAL_0_OPCODE_X0 = 64, - SEQB_SPECIAL_0_OPCODE_X1 = 33, - SEQH_SPECIAL_0_OPCODE_X0 = 65, - SEQH_SPECIAL_0_OPCODE_X1 = 34, - SEQIB_IMM_0_OPCODE_X0 = 9, - SEQIB_IMM_0_OPCODE_X1 = 12, - SEQIH_IMM_0_OPCODE_X0 = 10, - SEQIH_IMM_0_OPCODE_X1 = 13, - SEQI_IMM_0_OPCODE_X0 = 11, - SEQI_IMM_0_OPCODE_X1 = 14, - SEQI_OPCODE_Y0 = 12, - SEQI_OPCODE_Y1 = 10, - SEQ_SPECIAL_0_OPCODE_X0 = 66, - SEQ_SPECIAL_0_OPCODE_X1 = 35, - SEQ_SPECIAL_5_OPCODE_Y0 = 2, - SEQ_SPECIAL_5_OPCODE_Y1 = 2, - SHADD_IMM_0_OPCODE_X1 = 29, - SHL8II_IMM_0_OPCODE_SN = 3, - SHLB_SPECIAL_0_OPCODE_X0 = 67, - SHLB_SPECIAL_0_OPCODE_X1 = 36, - SHLH_SPECIAL_0_OPCODE_X0 = 68, - SHLH_SPECIAL_0_OPCODE_X1 = 37, - SHLIB_SHUN_0_OPCODE_X0 = 2, - SHLIB_SHUN_0_OPCODE_X1 = 2, - SHLIH_SHUN_0_OPCODE_X0 = 3, - SHLIH_SHUN_0_OPCODE_X1 = 3, - SHLI_SHUN_0_OPCODE_X0 = 4, - SHLI_SHUN_0_OPCODE_X1 = 4, - SHLI_SHUN_0_OPCODE_Y0 = 2, - SHLI_SHUN_0_OPCODE_Y1 = 2, - SHL_SPECIAL_0_OPCODE_X0 = 69, - SHL_SPECIAL_0_OPCODE_X1 = 38, - SHL_SPECIAL_3_OPCODE_Y0 = 1, - SHL_SPECIAL_3_OPCODE_Y1 = 1, - SHR1_RR_IMM_0_OPCODE_SN = 9, - SHRB_SPECIAL_0_OPCODE_X0 = 70, - SHRB_SPECIAL_0_OPCODE_X1 = 39, - SHRH_SPECIAL_0_OPCODE_X0 = 71, - SHRH_SPECIAL_0_OPCODE_X1 = 40, - SHRIB_SHUN_0_OPCODE_X0 = 5, - SHRIB_SHUN_0_OPCODE_X1 = 5, - SHRIH_SHUN_0_OPCODE_X0 = 6, - SHRIH_SHUN_0_OPCODE_X1 = 6, - SHRI_SHUN_0_OPCODE_X0 = 7, - SHRI_SHUN_0_OPCODE_X1 = 7, - SHRI_SHUN_0_OPCODE_Y0 = 3, - SHRI_SHUN_0_OPCODE_Y1 = 3, - SHR_SPECIAL_0_OPCODE_X0 = 72, - SHR_SPECIAL_0_OPCODE_X1 = 41, - SHR_SPECIAL_3_OPCODE_Y0 = 2, - SHR_SPECIAL_3_OPCODE_Y1 = 2, - SHUN_0_OPCODE_X0 = 7, - SHUN_0_OPCODE_X1 = 8, - SHUN_0_OPCODE_Y0 = 13, - SHUN_0_OPCODE_Y1 = 11, - SH_OPCODE_Y2 = 6, - SH_SPECIAL_0_OPCODE_X1 = 42, - SLTB_SPECIAL_0_OPCODE_X0 = 73, - SLTB_SPECIAL_0_OPCODE_X1 = 43, - SLTB_U_SPECIAL_0_OPCODE_X0 = 74, - SLTB_U_SPECIAL_0_OPCODE_X1 = 44, - SLTEB_SPECIAL_0_OPCODE_X0 = 75, - SLTEB_SPECIAL_0_OPCODE_X1 = 45, - SLTEB_U_SPECIAL_0_OPCODE_X0 = 76, - SLTEB_U_SPECIAL_0_OPCODE_X1 = 46, - SLTEH_SPECIAL_0_OPCODE_X0 = 77, - SLTEH_SPECIAL_0_OPCODE_X1 = 47, - SLTEH_U_SPECIAL_0_OPCODE_X0 = 78, - SLTEH_U_SPECIAL_0_OPCODE_X1 = 48, - SLTE_SPECIAL_0_OPCODE_X0 = 79, - SLTE_SPECIAL_0_OPCODE_X1 = 49, - SLTE_SPECIAL_4_OPCODE_Y0 = 0, - SLTE_SPECIAL_4_OPCODE_Y1 = 0, - SLTE_U_SPECIAL_0_OPCODE_X0 = 80, - SLTE_U_SPECIAL_0_OPCODE_X1 = 50, - SLTE_U_SPECIAL_4_OPCODE_Y0 = 1, - SLTE_U_SPECIAL_4_OPCODE_Y1 = 1, - SLTH_SPECIAL_0_OPCODE_X0 = 81, - SLTH_SPECIAL_0_OPCODE_X1 = 51, - SLTH_U_SPECIAL_0_OPCODE_X0 = 82, - SLTH_U_SPECIAL_0_OPCODE_X1 = 52, - SLTIB_IMM_0_OPCODE_X0 = 12, - SLTIB_IMM_0_OPCODE_X1 = 15, - SLTIB_U_IMM_0_OPCODE_X0 = 13, - SLTIB_U_IMM_0_OPCODE_X1 = 16, - SLTIH_IMM_0_OPCODE_X0 = 14, - SLTIH_IMM_0_OPCODE_X1 = 17, - SLTIH_U_IMM_0_OPCODE_X0 = 15, - SLTIH_U_IMM_0_OPCODE_X1 = 18, - SLTI_IMM_0_OPCODE_X0 = 16, - SLTI_IMM_0_OPCODE_X1 = 19, - SLTI_OPCODE_Y0 = 14, - SLTI_OPCODE_Y1 = 12, - SLTI_U_IMM_0_OPCODE_X0 = 17, - SLTI_U_IMM_0_OPCODE_X1 = 20, - SLTI_U_OPCODE_Y0 = 15, - SLTI_U_OPCODE_Y1 = 13, - SLT_SPECIAL_0_OPCODE_X0 = 83, - SLT_SPECIAL_0_OPCODE_X1 = 53, - SLT_SPECIAL_4_OPCODE_Y0 = 2, - SLT_SPECIAL_4_OPCODE_Y1 = 2, - SLT_U_SPECIAL_0_OPCODE_X0 = 84, - SLT_U_SPECIAL_0_OPCODE_X1 = 54, - SLT_U_SPECIAL_4_OPCODE_Y0 = 3, - SLT_U_SPECIAL_4_OPCODE_Y1 = 3, - SNEB_SPECIAL_0_OPCODE_X0 = 85, - SNEB_SPECIAL_0_OPCODE_X1 = 55, - SNEH_SPECIAL_0_OPCODE_X0 = 86, - SNEH_SPECIAL_0_OPCODE_X1 = 56, - SNE_SPECIAL_0_OPCODE_X0 = 87, - SNE_SPECIAL_0_OPCODE_X1 = 57, - SNE_SPECIAL_5_OPCODE_Y0 = 3, - SNE_SPECIAL_5_OPCODE_Y1 = 3, - SPECIAL_0_OPCODE_X0 = 0, - SPECIAL_0_OPCODE_X1 = 1, - SPECIAL_0_OPCODE_Y0 = 1, - SPECIAL_0_OPCODE_Y1 = 1, - SPECIAL_1_OPCODE_Y0 = 2, - SPECIAL_1_OPCODE_Y1 = 2, - SPECIAL_2_OPCODE_Y0 = 3, - SPECIAL_2_OPCODE_Y1 = 3, - SPECIAL_3_OPCODE_Y0 = 4, - SPECIAL_3_OPCODE_Y1 = 4, - SPECIAL_4_OPCODE_Y0 = 5, - SPECIAL_4_OPCODE_Y1 = 5, - SPECIAL_5_OPCODE_Y0 = 6, - SPECIAL_5_OPCODE_Y1 = 6, - SPECIAL_6_OPCODE_Y0 = 7, - SPECIAL_7_OPCODE_Y0 = 8, - SRAB_SPECIAL_0_OPCODE_X0 = 88, - SRAB_SPECIAL_0_OPCODE_X1 = 58, - SRAH_SPECIAL_0_OPCODE_X0 = 89, - SRAH_SPECIAL_0_OPCODE_X1 = 59, - SRAIB_SHUN_0_OPCODE_X0 = 8, - SRAIB_SHUN_0_OPCODE_X1 = 8, - SRAIH_SHUN_0_OPCODE_X0 = 9, - SRAIH_SHUN_0_OPCODE_X1 = 9, - SRAI_SHUN_0_OPCODE_X0 = 10, - SRAI_SHUN_0_OPCODE_X1 = 10, - SRAI_SHUN_0_OPCODE_Y0 = 4, - SRAI_SHUN_0_OPCODE_Y1 = 4, - SRA_SPECIAL_0_OPCODE_X0 = 90, - SRA_SPECIAL_0_OPCODE_X1 = 60, - SRA_SPECIAL_3_OPCODE_Y0 = 3, - SRA_SPECIAL_3_OPCODE_Y1 = 3, - SUBBS_U_SPECIAL_0_OPCODE_X0 = 100, - SUBBS_U_SPECIAL_0_OPCODE_X1 = 70, - SUBB_SPECIAL_0_OPCODE_X0 = 91, - SUBB_SPECIAL_0_OPCODE_X1 = 61, - SUBHS_SPECIAL_0_OPCODE_X0 = 101, - SUBHS_SPECIAL_0_OPCODE_X1 = 71, - SUBH_SPECIAL_0_OPCODE_X0 = 92, - SUBH_SPECIAL_0_OPCODE_X1 = 62, - SUBS_SPECIAL_0_OPCODE_X0 = 97, - SUBS_SPECIAL_0_OPCODE_X1 = 67, - SUB_SPECIAL_0_OPCODE_X0 = 93, - SUB_SPECIAL_0_OPCODE_X1 = 63, - SUB_SPECIAL_0_OPCODE_Y0 = 3, - SUB_SPECIAL_0_OPCODE_Y1 = 3, - SWADD_IMM_0_OPCODE_X1 = 30, - SWINT0_UN_0_SHUN_0_OPCODE_X1 = 18, - SWINT1_UN_0_SHUN_0_OPCODE_X1 = 19, - SWINT2_UN_0_SHUN_0_OPCODE_X1 = 20, - SWINT3_UN_0_SHUN_0_OPCODE_X1 = 21, - SW_OPCODE_Y2 = 7, - SW_SPECIAL_0_OPCODE_X1 = 64, - TBLIDXB0_UN_0_SHUN_0_OPCODE_X0 = 8, - TBLIDXB0_UN_0_SHUN_0_OPCODE_Y0 = 8, - TBLIDXB1_UN_0_SHUN_0_OPCODE_X0 = 9, - TBLIDXB1_UN_0_SHUN_0_OPCODE_Y0 = 9, - TBLIDXB2_UN_0_SHUN_0_OPCODE_X0 = 10, - TBLIDXB2_UN_0_SHUN_0_OPCODE_Y0 = 10, - TBLIDXB3_UN_0_SHUN_0_OPCODE_X0 = 11, - TBLIDXB3_UN_0_SHUN_0_OPCODE_Y0 = 11, - TNS_UN_0_SHUN_0_OPCODE_X1 = 22, - UN_0_SHUN_0_OPCODE_X0 = 11, - UN_0_SHUN_0_OPCODE_X1 = 11, - UN_0_SHUN_0_OPCODE_Y0 = 5, - UN_0_SHUN_0_OPCODE_Y1 = 5, - WH64_UN_0_SHUN_0_OPCODE_X1 = 23, - XORI_IMM_0_OPCODE_X0 = 2, - XORI_IMM_0_OPCODE_X1 = 21, - XOR_SPECIAL_0_OPCODE_X0 = 94, - XOR_SPECIAL_0_OPCODE_X1 = 65, - XOR_SPECIAL_2_OPCODE_Y0 = 3, - XOR_SPECIAL_2_OPCODE_Y1 = 3 -}; - -#endif /* !_TILE_OPCODE_CONSTANTS_H */ diff --git a/arch/tile/include/asm/opcode-tile.h b/arch/tile/include/asm/tile-desc.h similarity index 56% rename from arch/tile/include/asm/opcode-tile.h rename to arch/tile/include/asm/tile-desc.h index ba38959137d7..43849bf79dcb 100644 --- a/arch/tile/include/asm/opcode-tile.h +++ b/arch/tile/include/asm/tile-desc.h @@ -1,5 +1,5 @@ /* - * Copyright 2010 Tilera Corporation. All Rights Reserved. + * Copyright 2011 Tilera Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,19 +12,8 @@ * more details. */ -#ifndef _ASM_TILE_OPCODE_TILE_H -#define _ASM_TILE_OPCODE_TILE_H - -#include - -#if CHIP_WORD_SIZE() == 64 -#include +#ifndef __tilegx__ +#include #else -#include +#include #endif - -/* These definitions are not correct for TILE64, so just avoid them. */ -#undef TILE_ELF_MACHINE_CODE -#undef TILE_ELF_NAME - -#endif /* _ASM_TILE_OPCODE_TILE_H */ diff --git a/arch/tile/include/asm/tile-desc_32.h b/arch/tile/include/asm/tile-desc_32.h new file mode 100644 index 000000000000..f09c5c43b0b2 --- /dev/null +++ b/arch/tile/include/asm/tile-desc_32.h @@ -0,0 +1,553 @@ +/* TILEPro opcode information. + * + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * + * + * + * + */ + +#ifndef opcode_tilepro_h +#define opcode_tilepro_h + +#include + + +enum +{ + TILEPRO_MAX_OPERANDS = 5 /* mm */ +}; + +typedef enum +{ + TILEPRO_OPC_BPT, + TILEPRO_OPC_INFO, + TILEPRO_OPC_INFOL, + TILEPRO_OPC_J, + TILEPRO_OPC_JAL, + TILEPRO_OPC_MOVE, + TILEPRO_OPC_MOVE_SN, + TILEPRO_OPC_MOVEI, + TILEPRO_OPC_MOVEI_SN, + TILEPRO_OPC_MOVELI, + TILEPRO_OPC_MOVELI_SN, + TILEPRO_OPC_MOVELIS, + TILEPRO_OPC_PREFETCH, + TILEPRO_OPC_RAISE, + TILEPRO_OPC_ADD, + TILEPRO_OPC_ADD_SN, + TILEPRO_OPC_ADDB, + TILEPRO_OPC_ADDB_SN, + TILEPRO_OPC_ADDBS_U, + TILEPRO_OPC_ADDBS_U_SN, + TILEPRO_OPC_ADDH, + TILEPRO_OPC_ADDH_SN, + TILEPRO_OPC_ADDHS, + TILEPRO_OPC_ADDHS_SN, + TILEPRO_OPC_ADDI, + TILEPRO_OPC_ADDI_SN, + TILEPRO_OPC_ADDIB, + TILEPRO_OPC_ADDIB_SN, + TILEPRO_OPC_ADDIH, + TILEPRO_OPC_ADDIH_SN, + TILEPRO_OPC_ADDLI, + TILEPRO_OPC_ADDLI_SN, + TILEPRO_OPC_ADDLIS, + TILEPRO_OPC_ADDS, + TILEPRO_OPC_ADDS_SN, + TILEPRO_OPC_ADIFFB_U, + TILEPRO_OPC_ADIFFB_U_SN, + TILEPRO_OPC_ADIFFH, + TILEPRO_OPC_ADIFFH_SN, + TILEPRO_OPC_AND, + TILEPRO_OPC_AND_SN, + TILEPRO_OPC_ANDI, + TILEPRO_OPC_ANDI_SN, + TILEPRO_OPC_AULI, + TILEPRO_OPC_AVGB_U, + TILEPRO_OPC_AVGB_U_SN, + TILEPRO_OPC_AVGH, + TILEPRO_OPC_AVGH_SN, + TILEPRO_OPC_BBNS, + TILEPRO_OPC_BBNS_SN, + TILEPRO_OPC_BBNST, + TILEPRO_OPC_BBNST_SN, + TILEPRO_OPC_BBS, + TILEPRO_OPC_BBS_SN, + TILEPRO_OPC_BBST, + TILEPRO_OPC_BBST_SN, + TILEPRO_OPC_BGEZ, + TILEPRO_OPC_BGEZ_SN, + TILEPRO_OPC_BGEZT, + TILEPRO_OPC_BGEZT_SN, + TILEPRO_OPC_BGZ, + TILEPRO_OPC_BGZ_SN, + TILEPRO_OPC_BGZT, + TILEPRO_OPC_BGZT_SN, + TILEPRO_OPC_BITX, + TILEPRO_OPC_BITX_SN, + TILEPRO_OPC_BLEZ, + TILEPRO_OPC_BLEZ_SN, + TILEPRO_OPC_BLEZT, + TILEPRO_OPC_BLEZT_SN, + TILEPRO_OPC_BLZ, + TILEPRO_OPC_BLZ_SN, + TILEPRO_OPC_BLZT, + TILEPRO_OPC_BLZT_SN, + TILEPRO_OPC_BNZ, + TILEPRO_OPC_BNZ_SN, + TILEPRO_OPC_BNZT, + TILEPRO_OPC_BNZT_SN, + TILEPRO_OPC_BYTEX, + TILEPRO_OPC_BYTEX_SN, + TILEPRO_OPC_BZ, + TILEPRO_OPC_BZ_SN, + TILEPRO_OPC_BZT, + TILEPRO_OPC_BZT_SN, + TILEPRO_OPC_CLZ, + TILEPRO_OPC_CLZ_SN, + TILEPRO_OPC_CRC32_32, + TILEPRO_OPC_CRC32_32_SN, + TILEPRO_OPC_CRC32_8, + TILEPRO_OPC_CRC32_8_SN, + TILEPRO_OPC_CTZ, + TILEPRO_OPC_CTZ_SN, + TILEPRO_OPC_DRAIN, + TILEPRO_OPC_DTLBPR, + TILEPRO_OPC_DWORD_ALIGN, + TILEPRO_OPC_DWORD_ALIGN_SN, + TILEPRO_OPC_FINV, + TILEPRO_OPC_FLUSH, + TILEPRO_OPC_FNOP, + TILEPRO_OPC_ICOH, + TILEPRO_OPC_ILL, + TILEPRO_OPC_INTHB, + TILEPRO_OPC_INTHB_SN, + TILEPRO_OPC_INTHH, + TILEPRO_OPC_INTHH_SN, + TILEPRO_OPC_INTLB, + TILEPRO_OPC_INTLB_SN, + TILEPRO_OPC_INTLH, + TILEPRO_OPC_INTLH_SN, + TILEPRO_OPC_INV, + TILEPRO_OPC_IRET, + TILEPRO_OPC_JALB, + TILEPRO_OPC_JALF, + TILEPRO_OPC_JALR, + TILEPRO_OPC_JALRP, + TILEPRO_OPC_JB, + TILEPRO_OPC_JF, + TILEPRO_OPC_JR, + TILEPRO_OPC_JRP, + TILEPRO_OPC_LB, + TILEPRO_OPC_LB_SN, + TILEPRO_OPC_LB_U, + TILEPRO_OPC_LB_U_SN, + TILEPRO_OPC_LBADD, + TILEPRO_OPC_LBADD_SN, + TILEPRO_OPC_LBADD_U, + TILEPRO_OPC_LBADD_U_SN, + TILEPRO_OPC_LH, + TILEPRO_OPC_LH_SN, + TILEPRO_OPC_LH_U, + TILEPRO_OPC_LH_U_SN, + TILEPRO_OPC_LHADD, + TILEPRO_OPC_LHADD_SN, + TILEPRO_OPC_LHADD_U, + TILEPRO_OPC_LHADD_U_SN, + TILEPRO_OPC_LNK, + TILEPRO_OPC_LNK_SN, + TILEPRO_OPC_LW, + TILEPRO_OPC_LW_SN, + TILEPRO_OPC_LW_NA, + TILEPRO_OPC_LW_NA_SN, + TILEPRO_OPC_LWADD, + TILEPRO_OPC_LWADD_SN, + TILEPRO_OPC_LWADD_NA, + TILEPRO_OPC_LWADD_NA_SN, + TILEPRO_OPC_MAXB_U, + TILEPRO_OPC_MAXB_U_SN, + TILEPRO_OPC_MAXH, + TILEPRO_OPC_MAXH_SN, + TILEPRO_OPC_MAXIB_U, + TILEPRO_OPC_MAXIB_U_SN, + TILEPRO_OPC_MAXIH, + TILEPRO_OPC_MAXIH_SN, + TILEPRO_OPC_MF, + TILEPRO_OPC_MFSPR, + TILEPRO_OPC_MINB_U, + TILEPRO_OPC_MINB_U_SN, + TILEPRO_OPC_MINH, + TILEPRO_OPC_MINH_SN, + TILEPRO_OPC_MINIB_U, + TILEPRO_OPC_MINIB_U_SN, + TILEPRO_OPC_MINIH, + TILEPRO_OPC_MINIH_SN, + TILEPRO_OPC_MM, + TILEPRO_OPC_MNZ, + TILEPRO_OPC_MNZ_SN, + TILEPRO_OPC_MNZB, + TILEPRO_OPC_MNZB_SN, + TILEPRO_OPC_MNZH, + TILEPRO_OPC_MNZH_SN, + TILEPRO_OPC_MTSPR, + TILEPRO_OPC_MULHH_SS, + TILEPRO_OPC_MULHH_SS_SN, + TILEPRO_OPC_MULHH_SU, + TILEPRO_OPC_MULHH_SU_SN, + TILEPRO_OPC_MULHH_UU, + TILEPRO_OPC_MULHH_UU_SN, + TILEPRO_OPC_MULHHA_SS, + TILEPRO_OPC_MULHHA_SS_SN, + TILEPRO_OPC_MULHHA_SU, + TILEPRO_OPC_MULHHA_SU_SN, + TILEPRO_OPC_MULHHA_UU, + TILEPRO_OPC_MULHHA_UU_SN, + TILEPRO_OPC_MULHHSA_UU, + TILEPRO_OPC_MULHHSA_UU_SN, + TILEPRO_OPC_MULHL_SS, + TILEPRO_OPC_MULHL_SS_SN, + TILEPRO_OPC_MULHL_SU, + TILEPRO_OPC_MULHL_SU_SN, + TILEPRO_OPC_MULHL_US, + TILEPRO_OPC_MULHL_US_SN, + TILEPRO_OPC_MULHL_UU, + TILEPRO_OPC_MULHL_UU_SN, + TILEPRO_OPC_MULHLA_SS, + TILEPRO_OPC_MULHLA_SS_SN, + TILEPRO_OPC_MULHLA_SU, + TILEPRO_OPC_MULHLA_SU_SN, + TILEPRO_OPC_MULHLA_US, + TILEPRO_OPC_MULHLA_US_SN, + TILEPRO_OPC_MULHLA_UU, + TILEPRO_OPC_MULHLA_UU_SN, + TILEPRO_OPC_MULHLSA_UU, + TILEPRO_OPC_MULHLSA_UU_SN, + TILEPRO_OPC_MULLL_SS, + TILEPRO_OPC_MULLL_SS_SN, + TILEPRO_OPC_MULLL_SU, + TILEPRO_OPC_MULLL_SU_SN, + TILEPRO_OPC_MULLL_UU, + TILEPRO_OPC_MULLL_UU_SN, + TILEPRO_OPC_MULLLA_SS, + TILEPRO_OPC_MULLLA_SS_SN, + TILEPRO_OPC_MULLLA_SU, + TILEPRO_OPC_MULLLA_SU_SN, + TILEPRO_OPC_MULLLA_UU, + TILEPRO_OPC_MULLLA_UU_SN, + TILEPRO_OPC_MULLLSA_UU, + TILEPRO_OPC_MULLLSA_UU_SN, + TILEPRO_OPC_MVNZ, + TILEPRO_OPC_MVNZ_SN, + TILEPRO_OPC_MVZ, + TILEPRO_OPC_MVZ_SN, + TILEPRO_OPC_MZ, + TILEPRO_OPC_MZ_SN, + TILEPRO_OPC_MZB, + TILEPRO_OPC_MZB_SN, + TILEPRO_OPC_MZH, + TILEPRO_OPC_MZH_SN, + TILEPRO_OPC_NAP, + TILEPRO_OPC_NOP, + TILEPRO_OPC_NOR, + TILEPRO_OPC_NOR_SN, + TILEPRO_OPC_OR, + TILEPRO_OPC_OR_SN, + TILEPRO_OPC_ORI, + TILEPRO_OPC_ORI_SN, + TILEPRO_OPC_PACKBS_U, + TILEPRO_OPC_PACKBS_U_SN, + TILEPRO_OPC_PACKHB, + TILEPRO_OPC_PACKHB_SN, + TILEPRO_OPC_PACKHS, + TILEPRO_OPC_PACKHS_SN, + TILEPRO_OPC_PACKLB, + TILEPRO_OPC_PACKLB_SN, + TILEPRO_OPC_PCNT, + TILEPRO_OPC_PCNT_SN, + TILEPRO_OPC_RL, + TILEPRO_OPC_RL_SN, + TILEPRO_OPC_RLI, + TILEPRO_OPC_RLI_SN, + TILEPRO_OPC_S1A, + TILEPRO_OPC_S1A_SN, + TILEPRO_OPC_S2A, + TILEPRO_OPC_S2A_SN, + TILEPRO_OPC_S3A, + TILEPRO_OPC_S3A_SN, + TILEPRO_OPC_SADAB_U, + TILEPRO_OPC_SADAB_U_SN, + TILEPRO_OPC_SADAH, + TILEPRO_OPC_SADAH_SN, + TILEPRO_OPC_SADAH_U, + TILEPRO_OPC_SADAH_U_SN, + TILEPRO_OPC_SADB_U, + TILEPRO_OPC_SADB_U_SN, + TILEPRO_OPC_SADH, + TILEPRO_OPC_SADH_SN, + TILEPRO_OPC_SADH_U, + TILEPRO_OPC_SADH_U_SN, + TILEPRO_OPC_SB, + TILEPRO_OPC_SBADD, + TILEPRO_OPC_SEQ, + TILEPRO_OPC_SEQ_SN, + TILEPRO_OPC_SEQB, + TILEPRO_OPC_SEQB_SN, + TILEPRO_OPC_SEQH, + TILEPRO_OPC_SEQH_SN, + TILEPRO_OPC_SEQI, + TILEPRO_OPC_SEQI_SN, + TILEPRO_OPC_SEQIB, + TILEPRO_OPC_SEQIB_SN, + TILEPRO_OPC_SEQIH, + TILEPRO_OPC_SEQIH_SN, + TILEPRO_OPC_SH, + TILEPRO_OPC_SHADD, + TILEPRO_OPC_SHL, + TILEPRO_OPC_SHL_SN, + TILEPRO_OPC_SHLB, + TILEPRO_OPC_SHLB_SN, + TILEPRO_OPC_SHLH, + TILEPRO_OPC_SHLH_SN, + TILEPRO_OPC_SHLI, + TILEPRO_OPC_SHLI_SN, + TILEPRO_OPC_SHLIB, + TILEPRO_OPC_SHLIB_SN, + TILEPRO_OPC_SHLIH, + TILEPRO_OPC_SHLIH_SN, + TILEPRO_OPC_SHR, + TILEPRO_OPC_SHR_SN, + TILEPRO_OPC_SHRB, + TILEPRO_OPC_SHRB_SN, + TILEPRO_OPC_SHRH, + TILEPRO_OPC_SHRH_SN, + TILEPRO_OPC_SHRI, + TILEPRO_OPC_SHRI_SN, + TILEPRO_OPC_SHRIB, + TILEPRO_OPC_SHRIB_SN, + TILEPRO_OPC_SHRIH, + TILEPRO_OPC_SHRIH_SN, + TILEPRO_OPC_SLT, + TILEPRO_OPC_SLT_SN, + TILEPRO_OPC_SLT_U, + TILEPRO_OPC_SLT_U_SN, + TILEPRO_OPC_SLTB, + TILEPRO_OPC_SLTB_SN, + TILEPRO_OPC_SLTB_U, + TILEPRO_OPC_SLTB_U_SN, + TILEPRO_OPC_SLTE, + TILEPRO_OPC_SLTE_SN, + TILEPRO_OPC_SLTE_U, + TILEPRO_OPC_SLTE_U_SN, + TILEPRO_OPC_SLTEB, + TILEPRO_OPC_SLTEB_SN, + TILEPRO_OPC_SLTEB_U, + TILEPRO_OPC_SLTEB_U_SN, + TILEPRO_OPC_SLTEH, + TILEPRO_OPC_SLTEH_SN, + TILEPRO_OPC_SLTEH_U, + TILEPRO_OPC_SLTEH_U_SN, + TILEPRO_OPC_SLTH, + TILEPRO_OPC_SLTH_SN, + TILEPRO_OPC_SLTH_U, + TILEPRO_OPC_SLTH_U_SN, + TILEPRO_OPC_SLTI, + TILEPRO_OPC_SLTI_SN, + TILEPRO_OPC_SLTI_U, + TILEPRO_OPC_SLTI_U_SN, + TILEPRO_OPC_SLTIB, + TILEPRO_OPC_SLTIB_SN, + TILEPRO_OPC_SLTIB_U, + TILEPRO_OPC_SLTIB_U_SN, + TILEPRO_OPC_SLTIH, + TILEPRO_OPC_SLTIH_SN, + TILEPRO_OPC_SLTIH_U, + TILEPRO_OPC_SLTIH_U_SN, + TILEPRO_OPC_SNE, + TILEPRO_OPC_SNE_SN, + TILEPRO_OPC_SNEB, + TILEPRO_OPC_SNEB_SN, + TILEPRO_OPC_SNEH, + TILEPRO_OPC_SNEH_SN, + TILEPRO_OPC_SRA, + TILEPRO_OPC_SRA_SN, + TILEPRO_OPC_SRAB, + TILEPRO_OPC_SRAB_SN, + TILEPRO_OPC_SRAH, + TILEPRO_OPC_SRAH_SN, + TILEPRO_OPC_SRAI, + TILEPRO_OPC_SRAI_SN, + TILEPRO_OPC_SRAIB, + TILEPRO_OPC_SRAIB_SN, + TILEPRO_OPC_SRAIH, + TILEPRO_OPC_SRAIH_SN, + TILEPRO_OPC_SUB, + TILEPRO_OPC_SUB_SN, + TILEPRO_OPC_SUBB, + TILEPRO_OPC_SUBB_SN, + TILEPRO_OPC_SUBBS_U, + TILEPRO_OPC_SUBBS_U_SN, + TILEPRO_OPC_SUBH, + TILEPRO_OPC_SUBH_SN, + TILEPRO_OPC_SUBHS, + TILEPRO_OPC_SUBHS_SN, + TILEPRO_OPC_SUBS, + TILEPRO_OPC_SUBS_SN, + TILEPRO_OPC_SW, + TILEPRO_OPC_SWADD, + TILEPRO_OPC_SWINT0, + TILEPRO_OPC_SWINT1, + TILEPRO_OPC_SWINT2, + TILEPRO_OPC_SWINT3, + TILEPRO_OPC_TBLIDXB0, + TILEPRO_OPC_TBLIDXB0_SN, + TILEPRO_OPC_TBLIDXB1, + TILEPRO_OPC_TBLIDXB1_SN, + TILEPRO_OPC_TBLIDXB2, + TILEPRO_OPC_TBLIDXB2_SN, + TILEPRO_OPC_TBLIDXB3, + TILEPRO_OPC_TBLIDXB3_SN, + TILEPRO_OPC_TNS, + TILEPRO_OPC_TNS_SN, + TILEPRO_OPC_WH64, + TILEPRO_OPC_XOR, + TILEPRO_OPC_XOR_SN, + TILEPRO_OPC_XORI, + TILEPRO_OPC_XORI_SN, + TILEPRO_OPC_NONE +} tilepro_mnemonic; + + + + +typedef enum +{ + TILEPRO_PIPELINE_X0, + TILEPRO_PIPELINE_X1, + TILEPRO_PIPELINE_Y0, + TILEPRO_PIPELINE_Y1, + TILEPRO_PIPELINE_Y2, +} tilepro_pipeline; + +#define tilepro_is_x_pipeline(p) ((int)(p) <= (int)TILEPRO_PIPELINE_X1) + +typedef enum +{ + TILEPRO_OP_TYPE_REGISTER, + TILEPRO_OP_TYPE_IMMEDIATE, + TILEPRO_OP_TYPE_ADDRESS, + TILEPRO_OP_TYPE_SPR +} tilepro_operand_type; + +struct tilepro_operand +{ + /* Is this operand a register, immediate or address? */ + tilepro_operand_type type; + + /* The default relocation type for this operand. */ + signed int default_reloc : 16; + + /* How many bits is this value? (used for range checking) */ + unsigned int num_bits : 5; + + /* Is the value signed? (used for range checking) */ + unsigned int is_signed : 1; + + /* Is this operand a source register? */ + unsigned int is_src_reg : 1; + + /* Is this operand written? (i.e. is it a destination register) */ + unsigned int is_dest_reg : 1; + + /* Is this operand PC-relative? */ + unsigned int is_pc_relative : 1; + + /* By how many bits do we right shift the value before inserting? */ + unsigned int rightshift : 2; + + /* Return the bits for this operand to be ORed into an existing bundle. */ + tilepro_bundle_bits (*insert) (int op); + + /* Extract this operand and return it. */ + unsigned int (*extract) (tilepro_bundle_bits bundle); +}; + + +extern const struct tilepro_operand tilepro_operands[]; + +/* One finite-state machine per pipe for rapid instruction decoding. */ +extern const unsigned short * const +tilepro_bundle_decoder_fsms[TILEPRO_NUM_PIPELINE_ENCODINGS]; + + +struct tilepro_opcode +{ + /* The opcode mnemonic, e.g. "add" */ + const char *name; + + /* The enum value for this mnemonic. */ + tilepro_mnemonic mnemonic; + + /* A bit mask of which of the five pipes this instruction + is compatible with: + X0 0x01 + X1 0x02 + Y0 0x04 + Y1 0x08 + Y2 0x10 */ + unsigned char pipes; + + /* How many operands are there? */ + unsigned char num_operands; + + /* Which register does this write implicitly, or TREG_ZERO if none? */ + unsigned char implicitly_written_register; + + /* Can this be bundled with other instructions (almost always true). */ + unsigned char can_bundle; + + /* The description of the operands. Each of these is an + * index into the tilepro_operands[] table. */ + unsigned char operands[TILEPRO_NUM_PIPELINE_ENCODINGS][TILEPRO_MAX_OPERANDS]; + +}; + +extern const struct tilepro_opcode tilepro_opcodes[]; + + +/* Used for non-textual disassembly into structs. */ +struct tilepro_decoded_instruction +{ + const struct tilepro_opcode *opcode; + const struct tilepro_operand *operands[TILEPRO_MAX_OPERANDS]; + int operand_values[TILEPRO_MAX_OPERANDS]; +}; + + +/* Disassemble a bundle into a struct for machine processing. */ +extern int parse_insn_tilepro(tilepro_bundle_bits bits, + unsigned int pc, + struct tilepro_decoded_instruction + decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE]); + + +/* Given a set of bundle bits and a specific pipe, returns which + * instruction the bundle contains in that pipe. + */ +extern const struct tilepro_opcode * +find_opcode(tilepro_bundle_bits bits, tilepro_pipeline pipe); + + + +#endif /* opcode_tilepro_h */ diff --git a/arch/tile/include/asm/tile-desc_64.h b/arch/tile/include/asm/tile-desc_64.h new file mode 100644 index 000000000000..1819efcba54d --- /dev/null +++ b/arch/tile/include/asm/tile-desc_64.h @@ -0,0 +1,483 @@ +/* TILE-Gx opcode information. + * + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * + * + * + * + */ + +#ifndef opcode_tile_h +#define opcode_tile_h + +#include + + +enum +{ + TILEGX_MAX_OPERANDS = 4 /* bfexts */ +}; + +typedef enum +{ + TILEGX_OPC_BPT, + TILEGX_OPC_INFO, + TILEGX_OPC_INFOL, + TILEGX_OPC_MOVE, + TILEGX_OPC_MOVEI, + TILEGX_OPC_MOVELI, + TILEGX_OPC_PREFETCH, + TILEGX_OPC_PREFETCH_ADD_L1, + TILEGX_OPC_PREFETCH_ADD_L1_FAULT, + TILEGX_OPC_PREFETCH_ADD_L2, + TILEGX_OPC_PREFETCH_ADD_L2_FAULT, + TILEGX_OPC_PREFETCH_ADD_L3, + TILEGX_OPC_PREFETCH_ADD_L3_FAULT, + TILEGX_OPC_PREFETCH_L1, + TILEGX_OPC_PREFETCH_L1_FAULT, + TILEGX_OPC_PREFETCH_L2, + TILEGX_OPC_PREFETCH_L2_FAULT, + TILEGX_OPC_PREFETCH_L3, + TILEGX_OPC_PREFETCH_L3_FAULT, + TILEGX_OPC_RAISE, + TILEGX_OPC_ADD, + TILEGX_OPC_ADDI, + TILEGX_OPC_ADDLI, + TILEGX_OPC_ADDX, + TILEGX_OPC_ADDXI, + TILEGX_OPC_ADDXLI, + TILEGX_OPC_ADDXSC, + TILEGX_OPC_AND, + TILEGX_OPC_ANDI, + TILEGX_OPC_BEQZ, + TILEGX_OPC_BEQZT, + TILEGX_OPC_BFEXTS, + TILEGX_OPC_BFEXTU, + TILEGX_OPC_BFINS, + TILEGX_OPC_BGEZ, + TILEGX_OPC_BGEZT, + TILEGX_OPC_BGTZ, + TILEGX_OPC_BGTZT, + TILEGX_OPC_BLBC, + TILEGX_OPC_BLBCT, + TILEGX_OPC_BLBS, + TILEGX_OPC_BLBST, + TILEGX_OPC_BLEZ, + TILEGX_OPC_BLEZT, + TILEGX_OPC_BLTZ, + TILEGX_OPC_BLTZT, + TILEGX_OPC_BNEZ, + TILEGX_OPC_BNEZT, + TILEGX_OPC_CLZ, + TILEGX_OPC_CMOVEQZ, + TILEGX_OPC_CMOVNEZ, + TILEGX_OPC_CMPEQ, + TILEGX_OPC_CMPEQI, + TILEGX_OPC_CMPEXCH, + TILEGX_OPC_CMPEXCH4, + TILEGX_OPC_CMPLES, + TILEGX_OPC_CMPLEU, + TILEGX_OPC_CMPLTS, + TILEGX_OPC_CMPLTSI, + TILEGX_OPC_CMPLTU, + TILEGX_OPC_CMPLTUI, + TILEGX_OPC_CMPNE, + TILEGX_OPC_CMUL, + TILEGX_OPC_CMULA, + TILEGX_OPC_CMULAF, + TILEGX_OPC_CMULF, + TILEGX_OPC_CMULFR, + TILEGX_OPC_CMULH, + TILEGX_OPC_CMULHR, + TILEGX_OPC_CRC32_32, + TILEGX_OPC_CRC32_8, + TILEGX_OPC_CTZ, + TILEGX_OPC_DBLALIGN, + TILEGX_OPC_DBLALIGN2, + TILEGX_OPC_DBLALIGN4, + TILEGX_OPC_DBLALIGN6, + TILEGX_OPC_DRAIN, + TILEGX_OPC_DTLBPR, + TILEGX_OPC_EXCH, + TILEGX_OPC_EXCH4, + TILEGX_OPC_FDOUBLE_ADD_FLAGS, + TILEGX_OPC_FDOUBLE_ADDSUB, + TILEGX_OPC_FDOUBLE_MUL_FLAGS, + TILEGX_OPC_FDOUBLE_PACK1, + TILEGX_OPC_FDOUBLE_PACK2, + TILEGX_OPC_FDOUBLE_SUB_FLAGS, + TILEGX_OPC_FDOUBLE_UNPACK_MAX, + TILEGX_OPC_FDOUBLE_UNPACK_MIN, + TILEGX_OPC_FETCHADD, + TILEGX_OPC_FETCHADD4, + TILEGX_OPC_FETCHADDGEZ, + TILEGX_OPC_FETCHADDGEZ4, + TILEGX_OPC_FETCHAND, + TILEGX_OPC_FETCHAND4, + TILEGX_OPC_FETCHOR, + TILEGX_OPC_FETCHOR4, + TILEGX_OPC_FINV, + TILEGX_OPC_FLUSH, + TILEGX_OPC_FLUSHWB, + TILEGX_OPC_FNOP, + TILEGX_OPC_FSINGLE_ADD1, + TILEGX_OPC_FSINGLE_ADDSUB2, + TILEGX_OPC_FSINGLE_MUL1, + TILEGX_OPC_FSINGLE_MUL2, + TILEGX_OPC_FSINGLE_PACK1, + TILEGX_OPC_FSINGLE_PACK2, + TILEGX_OPC_FSINGLE_SUB1, + TILEGX_OPC_ICOH, + TILEGX_OPC_ILL, + TILEGX_OPC_INV, + TILEGX_OPC_IRET, + TILEGX_OPC_J, + TILEGX_OPC_JAL, + TILEGX_OPC_JALR, + TILEGX_OPC_JALRP, + TILEGX_OPC_JR, + TILEGX_OPC_JRP, + TILEGX_OPC_LD, + TILEGX_OPC_LD1S, + TILEGX_OPC_LD1S_ADD, + TILEGX_OPC_LD1U, + TILEGX_OPC_LD1U_ADD, + TILEGX_OPC_LD2S, + TILEGX_OPC_LD2S_ADD, + TILEGX_OPC_LD2U, + TILEGX_OPC_LD2U_ADD, + TILEGX_OPC_LD4S, + TILEGX_OPC_LD4S_ADD, + TILEGX_OPC_LD4U, + TILEGX_OPC_LD4U_ADD, + TILEGX_OPC_LD_ADD, + TILEGX_OPC_LDNA, + TILEGX_OPC_LDNA_ADD, + TILEGX_OPC_LDNT, + TILEGX_OPC_LDNT1S, + TILEGX_OPC_LDNT1S_ADD, + TILEGX_OPC_LDNT1U, + TILEGX_OPC_LDNT1U_ADD, + TILEGX_OPC_LDNT2S, + TILEGX_OPC_LDNT2S_ADD, + TILEGX_OPC_LDNT2U, + TILEGX_OPC_LDNT2U_ADD, + TILEGX_OPC_LDNT4S, + TILEGX_OPC_LDNT4S_ADD, + TILEGX_OPC_LDNT4U, + TILEGX_OPC_LDNT4U_ADD, + TILEGX_OPC_LDNT_ADD, + TILEGX_OPC_LNK, + TILEGX_OPC_MF, + TILEGX_OPC_MFSPR, + TILEGX_OPC_MM, + TILEGX_OPC_MNZ, + TILEGX_OPC_MTSPR, + TILEGX_OPC_MUL_HS_HS, + TILEGX_OPC_MUL_HS_HU, + TILEGX_OPC_MUL_HS_LS, + TILEGX_OPC_MUL_HS_LU, + TILEGX_OPC_MUL_HU_HU, + TILEGX_OPC_MUL_HU_LS, + TILEGX_OPC_MUL_HU_LU, + TILEGX_OPC_MUL_LS_LS, + TILEGX_OPC_MUL_LS_LU, + TILEGX_OPC_MUL_LU_LU, + TILEGX_OPC_MULA_HS_HS, + TILEGX_OPC_MULA_HS_HU, + TILEGX_OPC_MULA_HS_LS, + TILEGX_OPC_MULA_HS_LU, + TILEGX_OPC_MULA_HU_HU, + TILEGX_OPC_MULA_HU_LS, + TILEGX_OPC_MULA_HU_LU, + TILEGX_OPC_MULA_LS_LS, + TILEGX_OPC_MULA_LS_LU, + TILEGX_OPC_MULA_LU_LU, + TILEGX_OPC_MULAX, + TILEGX_OPC_MULX, + TILEGX_OPC_MZ, + TILEGX_OPC_NAP, + TILEGX_OPC_NOP, + TILEGX_OPC_NOR, + TILEGX_OPC_OR, + TILEGX_OPC_ORI, + TILEGX_OPC_PCNT, + TILEGX_OPC_REVBITS, + TILEGX_OPC_REVBYTES, + TILEGX_OPC_ROTL, + TILEGX_OPC_ROTLI, + TILEGX_OPC_SHL, + TILEGX_OPC_SHL16INSLI, + TILEGX_OPC_SHL1ADD, + TILEGX_OPC_SHL1ADDX, + TILEGX_OPC_SHL2ADD, + TILEGX_OPC_SHL2ADDX, + TILEGX_OPC_SHL3ADD, + TILEGX_OPC_SHL3ADDX, + TILEGX_OPC_SHLI, + TILEGX_OPC_SHLX, + TILEGX_OPC_SHLXI, + TILEGX_OPC_SHRS, + TILEGX_OPC_SHRSI, + TILEGX_OPC_SHRU, + TILEGX_OPC_SHRUI, + TILEGX_OPC_SHRUX, + TILEGX_OPC_SHRUXI, + TILEGX_OPC_SHUFFLEBYTES, + TILEGX_OPC_ST, + TILEGX_OPC_ST1, + TILEGX_OPC_ST1_ADD, + TILEGX_OPC_ST2, + TILEGX_OPC_ST2_ADD, + TILEGX_OPC_ST4, + TILEGX_OPC_ST4_ADD, + TILEGX_OPC_ST_ADD, + TILEGX_OPC_STNT, + TILEGX_OPC_STNT1, + TILEGX_OPC_STNT1_ADD, + TILEGX_OPC_STNT2, + TILEGX_OPC_STNT2_ADD, + TILEGX_OPC_STNT4, + TILEGX_OPC_STNT4_ADD, + TILEGX_OPC_STNT_ADD, + TILEGX_OPC_SUB, + TILEGX_OPC_SUBX, + TILEGX_OPC_SUBXSC, + TILEGX_OPC_SWINT0, + TILEGX_OPC_SWINT1, + TILEGX_OPC_SWINT2, + TILEGX_OPC_SWINT3, + TILEGX_OPC_TBLIDXB0, + TILEGX_OPC_TBLIDXB1, + TILEGX_OPC_TBLIDXB2, + TILEGX_OPC_TBLIDXB3, + TILEGX_OPC_V1ADD, + TILEGX_OPC_V1ADDI, + TILEGX_OPC_V1ADDUC, + TILEGX_OPC_V1ADIFFU, + TILEGX_OPC_V1AVGU, + TILEGX_OPC_V1CMPEQ, + TILEGX_OPC_V1CMPEQI, + TILEGX_OPC_V1CMPLES, + TILEGX_OPC_V1CMPLEU, + TILEGX_OPC_V1CMPLTS, + TILEGX_OPC_V1CMPLTSI, + TILEGX_OPC_V1CMPLTU, + TILEGX_OPC_V1CMPLTUI, + TILEGX_OPC_V1CMPNE, + TILEGX_OPC_V1DDOTPU, + TILEGX_OPC_V1DDOTPUA, + TILEGX_OPC_V1DDOTPUS, + TILEGX_OPC_V1DDOTPUSA, + TILEGX_OPC_V1DOTP, + TILEGX_OPC_V1DOTPA, + TILEGX_OPC_V1DOTPU, + TILEGX_OPC_V1DOTPUA, + TILEGX_OPC_V1DOTPUS, + TILEGX_OPC_V1DOTPUSA, + TILEGX_OPC_V1INT_H, + TILEGX_OPC_V1INT_L, + TILEGX_OPC_V1MAXU, + TILEGX_OPC_V1MAXUI, + TILEGX_OPC_V1MINU, + TILEGX_OPC_V1MINUI, + TILEGX_OPC_V1MNZ, + TILEGX_OPC_V1MULTU, + TILEGX_OPC_V1MULU, + TILEGX_OPC_V1MULUS, + TILEGX_OPC_V1MZ, + TILEGX_OPC_V1SADAU, + TILEGX_OPC_V1SADU, + TILEGX_OPC_V1SHL, + TILEGX_OPC_V1SHLI, + TILEGX_OPC_V1SHRS, + TILEGX_OPC_V1SHRSI, + TILEGX_OPC_V1SHRU, + TILEGX_OPC_V1SHRUI, + TILEGX_OPC_V1SUB, + TILEGX_OPC_V1SUBUC, + TILEGX_OPC_V2ADD, + TILEGX_OPC_V2ADDI, + TILEGX_OPC_V2ADDSC, + TILEGX_OPC_V2ADIFFS, + TILEGX_OPC_V2AVGS, + TILEGX_OPC_V2CMPEQ, + TILEGX_OPC_V2CMPEQI, + TILEGX_OPC_V2CMPLES, + TILEGX_OPC_V2CMPLEU, + TILEGX_OPC_V2CMPLTS, + TILEGX_OPC_V2CMPLTSI, + TILEGX_OPC_V2CMPLTU, + TILEGX_OPC_V2CMPLTUI, + TILEGX_OPC_V2CMPNE, + TILEGX_OPC_V2DOTP, + TILEGX_OPC_V2DOTPA, + TILEGX_OPC_V2INT_H, + TILEGX_OPC_V2INT_L, + TILEGX_OPC_V2MAXS, + TILEGX_OPC_V2MAXSI, + TILEGX_OPC_V2MINS, + TILEGX_OPC_V2MINSI, + TILEGX_OPC_V2MNZ, + TILEGX_OPC_V2MULFSC, + TILEGX_OPC_V2MULS, + TILEGX_OPC_V2MULTS, + TILEGX_OPC_V2MZ, + TILEGX_OPC_V2PACKH, + TILEGX_OPC_V2PACKL, + TILEGX_OPC_V2PACKUC, + TILEGX_OPC_V2SADAS, + TILEGX_OPC_V2SADAU, + TILEGX_OPC_V2SADS, + TILEGX_OPC_V2SADU, + TILEGX_OPC_V2SHL, + TILEGX_OPC_V2SHLI, + TILEGX_OPC_V2SHLSC, + TILEGX_OPC_V2SHRS, + TILEGX_OPC_V2SHRSI, + TILEGX_OPC_V2SHRU, + TILEGX_OPC_V2SHRUI, + TILEGX_OPC_V2SUB, + TILEGX_OPC_V2SUBSC, + TILEGX_OPC_V4ADD, + TILEGX_OPC_V4ADDSC, + TILEGX_OPC_V4INT_H, + TILEGX_OPC_V4INT_L, + TILEGX_OPC_V4PACKSC, + TILEGX_OPC_V4SHL, + TILEGX_OPC_V4SHLSC, + TILEGX_OPC_V4SHRS, + TILEGX_OPC_V4SHRU, + TILEGX_OPC_V4SUB, + TILEGX_OPC_V4SUBSC, + TILEGX_OPC_WH64, + TILEGX_OPC_XOR, + TILEGX_OPC_XORI, + TILEGX_OPC_NONE +} tilegx_mnemonic; + + + +typedef enum +{ + TILEGX_PIPELINE_X0, + TILEGX_PIPELINE_X1, + TILEGX_PIPELINE_Y0, + TILEGX_PIPELINE_Y1, + TILEGX_PIPELINE_Y2, +} tilegx_pipeline; + +#define tilegx_is_x_pipeline(p) ((int)(p) <= (int)TILEGX_PIPELINE_X1) + +typedef enum +{ + TILEGX_OP_TYPE_REGISTER, + TILEGX_OP_TYPE_IMMEDIATE, + TILEGX_OP_TYPE_ADDRESS, + TILEGX_OP_TYPE_SPR +} tilegx_operand_type; + +struct tilegx_operand +{ + /* Is this operand a register, immediate or address? */ + tilegx_operand_type type; + + /* The default relocation type for this operand. */ + signed int default_reloc : 16; + + /* How many bits is this value? (used for range checking) */ + unsigned int num_bits : 5; + + /* Is the value signed? (used for range checking) */ + unsigned int is_signed : 1; + + /* Is this operand a source register? */ + unsigned int is_src_reg : 1; + + /* Is this operand written? (i.e. is it a destination register) */ + unsigned int is_dest_reg : 1; + + /* Is this operand PC-relative? */ + unsigned int is_pc_relative : 1; + + /* By how many bits do we right shift the value before inserting? */ + unsigned int rightshift : 2; + + /* Return the bits for this operand to be ORed into an existing bundle. */ + tilegx_bundle_bits (*insert) (int op); + + /* Extract this operand and return it. */ + unsigned int (*extract) (tilegx_bundle_bits bundle); +}; + + +extern const struct tilegx_operand tilegx_operands[]; + +/* One finite-state machine per pipe for rapid instruction decoding. */ +extern const unsigned short * const +tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS]; + + +struct tilegx_opcode +{ + /* The opcode mnemonic, e.g. "add" */ + const char *name; + + /* The enum value for this mnemonic. */ + tilegx_mnemonic mnemonic; + + /* A bit mask of which of the five pipes this instruction + is compatible with: + X0 0x01 + X1 0x02 + Y0 0x04 + Y1 0x08 + Y2 0x10 */ + unsigned char pipes; + + /* How many operands are there? */ + unsigned char num_operands; + + /* Which register does this write implicitly, or TREG_ZERO if none? */ + unsigned char implicitly_written_register; + + /* Can this be bundled with other instructions (almost always true). */ + unsigned char can_bundle; + + /* The description of the operands. Each of these is an + * index into the tilegx_operands[] table. */ + unsigned char operands[TILEGX_NUM_PIPELINE_ENCODINGS][TILEGX_MAX_OPERANDS]; + +}; + +extern const struct tilegx_opcode tilegx_opcodes[]; + +/* Used for non-textual disassembly into structs. */ +struct tilegx_decoded_instruction +{ + const struct tilegx_opcode *opcode; + const struct tilegx_operand *operands[TILEGX_MAX_OPERANDS]; + long long operand_values[TILEGX_MAX_OPERANDS]; +}; + + +/* Disassemble a bundle into a struct for machine processing. */ +extern int parse_insn_tilegx(tilegx_bundle_bits bits, + unsigned long long pc, + struct tilegx_decoded_instruction + decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]); + + + +#endif /* opcode_tilegx_h */ diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c index 1dc71eabfc5a..9092ce8aa6b4 100644 --- a/arch/tile/kernel/backtrace.c +++ b/arch/tile/kernel/backtrace.c @@ -1,5 +1,5 @@ /* - * Copyright 2010 Tilera Corporation. All Rights Reserved. + * Copyright 2011 Tilera Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,13 +15,11 @@ #include #include #include -#include +#include #include #ifdef __tilegx__ -#define tile_bundle_bits tilegx_bundle_bits #define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE -#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES #define tile_decoded_instruction tilegx_decoded_instruction #define tile_mnemonic tilegx_mnemonic #define parse_insn_tile parse_insn_tilegx @@ -35,7 +33,18 @@ #define OPCODE_STORE TILEGX_OPC_ST typedef long long bt_int_reg_t; #else -#define OPCODE_STORE TILE_OPC_SW +#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE +#define tile_decoded_instruction tilepro_decoded_instruction +#define tile_mnemonic tilepro_mnemonic +#define parse_insn_tile parse_insn_tilepro +#define TILE_OPC_IRET TILEPRO_OPC_IRET +#define TILE_OPC_ADDI TILEPRO_OPC_ADDI +#define TILE_OPC_ADDLI TILEPRO_OPC_ADDLI +#define TILE_OPC_INFO TILEPRO_OPC_INFO +#define TILE_OPC_INFOL TILEPRO_OPC_INFOL +#define TILE_OPC_JRP TILEPRO_OPC_JRP +#define TILE_OPC_MOVE TILEPRO_OPC_MOVE +#define OPCODE_STORE TILEPRO_OPC_SW typedef int bt_int_reg_t; #endif diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c index 28fa6ece9d3a..b90ab9925674 100644 --- a/arch/tile/kernel/module.c +++ b/arch/tile/kernel/module.c @@ -20,9 +20,9 @@ #include #include #include -#include #include #include +#include #ifdef __tilegx__ # define Elf_Rela Elf64_Rela diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 4032ca8e51b6..b7a879504086 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c @@ -25,9 +25,8 @@ #include #include #include -#include -#include #include +#include #define signExtend17(val) sign_extend((val), 17) #define TILE_X1_MASK (0xffffffffULL << 31) @@ -118,7 +117,7 @@ static tile_bundle_bits rewrite_load_store_unaligned( int val_reg, addr_reg, err, val; /* Get address and value registers */ - if (bundle & TILE_BUNDLE_Y_ENCODING_MASK) { + if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) { addr_reg = get_SrcA_Y2(bundle); val_reg = get_SrcBDest_Y2(bundle); } else if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) { @@ -229,7 +228,7 @@ P("\n"); } ++unaligned_fixup_count; - if (bundle & TILE_BUNDLE_Y_ENCODING_MASK) { + if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) { /* Convert the Y2 instruction to a prefetch. */ bundle &= ~(create_SrcBDest_Y2(-1) | create_Opcode_Y2(-1)); @@ -389,7 +388,7 @@ void single_step_once(struct pt_regs *regs) state->branch_next_pc = 0; state->update = 0; - if (!(bundle & TILE_BUNDLE_Y_ENCODING_MASK)) { + if (!(bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK)) { /* two wide, check for control flow */ int opcode = get_Opcode_X1(bundle); diff --git a/arch/tile/kernel/tile-desc_32.c b/arch/tile/kernel/tile-desc_32.c index 7e31a1285788..dd7bd1d8563c 100644 --- a/arch/tile/kernel/tile-desc_32.c +++ b/arch/tile/kernel/tile-desc_32.c @@ -1,3 +1,23 @@ +/* TILEPro opcode information. + * + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * + * + * + * + */ + /* This define is BFD_RELOC_##x for real bfd, or -1 for everyone else. */ #define BFD_RELOC(x) -1 @@ -6,1217 +26,1217 @@ #define TREG_SN 56 #define TREG_ZERO 63 -/* FIXME: Rename this. */ -#include - #include +#include -const struct tile_opcode tile_opcodes[395] = +const struct tilepro_opcode tilepro_opcodes[395] = { - { "bpt", TILE_OPC_BPT, 0x2, 0, TREG_ZERO, 0, + { "bpt", TILEPRO_OPC_BPT, 0x2, 0, TREG_ZERO, 0, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "info", TILE_OPC_INFO, 0xf, 1, TREG_ZERO, 1, + { "info", TILEPRO_OPC_INFO, 0xf, 1, TREG_ZERO, 1, { { 0 }, { 1 }, { 2 }, { 3 }, { 0, } }, }, - { "infol", TILE_OPC_INFOL, 0x3, 1, TREG_ZERO, 1, + { "infol", TILEPRO_OPC_INFOL, 0x3, 1, TREG_ZERO, 1, { { 4 }, { 5 }, { 0, }, { 0, }, { 0, } }, }, - { "j", TILE_OPC_J, 0x2, 1, TREG_ZERO, 1, + { "j", TILEPRO_OPC_J, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 6 }, { 0, }, { 0, }, { 0, } }, }, - { "jal", TILE_OPC_JAL, 0x2, 1, TREG_LR, 1, + { "jal", TILEPRO_OPC_JAL, 0x2, 1, TREG_LR, 1, { { 0, }, { 6 }, { 0, }, { 0, }, { 0, } }, }, - { "move", TILE_OPC_MOVE, 0xf, 2, TREG_ZERO, 1, + { "move", TILEPRO_OPC_MOVE, 0xf, 2, TREG_ZERO, 1, { { 7, 8 }, { 9, 10 }, { 11, 12 }, { 13, 14 }, { 0, } }, }, - { "move.sn", TILE_OPC_MOVE_SN, 0x3, 2, TREG_SN, 1, + { "move.sn", TILEPRO_OPC_MOVE_SN, 0x3, 2, TREG_SN, 1, { { 7, 8 }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "movei", TILE_OPC_MOVEI, 0xf, 2, TREG_ZERO, 1, + { "movei", TILEPRO_OPC_MOVEI, 0xf, 2, TREG_ZERO, 1, { { 7, 0 }, { 9, 1 }, { 11, 2 }, { 13, 3 }, { 0, } }, }, - { "movei.sn", TILE_OPC_MOVEI_SN, 0x3, 2, TREG_SN, 1, + { "movei.sn", TILEPRO_OPC_MOVEI_SN, 0x3, 2, TREG_SN, 1, { { 7, 0 }, { 9, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "moveli", TILE_OPC_MOVELI, 0x3, 2, TREG_ZERO, 1, + { "moveli", TILEPRO_OPC_MOVELI, 0x3, 2, TREG_ZERO, 1, { { 7, 4 }, { 9, 5 }, { 0, }, { 0, }, { 0, } }, }, - { "moveli.sn", TILE_OPC_MOVELI_SN, 0x3, 2, TREG_SN, 1, + { "moveli.sn", TILEPRO_OPC_MOVELI_SN, 0x3, 2, TREG_SN, 1, { { 7, 4 }, { 9, 5 }, { 0, }, { 0, }, { 0, } }, }, - { "movelis", TILE_OPC_MOVELIS, 0x3, 2, TREG_SN, 1, + { "movelis", TILEPRO_OPC_MOVELIS, 0x3, 2, TREG_SN, 1, { { 7, 4 }, { 9, 5 }, { 0, }, { 0, }, { 0, } }, }, - { "prefetch", TILE_OPC_PREFETCH, 0x12, 1, TREG_ZERO, 1, + { "prefetch", TILEPRO_OPC_PREFETCH, 0x12, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 15 } }, }, - { "raise", TILE_OPC_RAISE, 0x2, 0, TREG_ZERO, 1, + { "raise", TILEPRO_OPC_RAISE, 0x2, 0, TREG_ZERO, 1, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "add", TILE_OPC_ADD, 0xf, 3, TREG_ZERO, 1, + { "add", TILEPRO_OPC_ADD, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "add.sn", TILE_OPC_ADD_SN, 0x3, 3, TREG_SN, 1, + { "add.sn", TILEPRO_OPC_ADD_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addb", TILE_OPC_ADDB, 0x3, 3, TREG_ZERO, 1, + { "addb", TILEPRO_OPC_ADDB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addb.sn", TILE_OPC_ADDB_SN, 0x3, 3, TREG_SN, 1, + { "addb.sn", TILEPRO_OPC_ADDB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addbs_u", TILE_OPC_ADDBS_U, 0x3, 3, TREG_ZERO, 1, + { "addbs_u", TILEPRO_OPC_ADDBS_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addbs_u.sn", TILE_OPC_ADDBS_U_SN, 0x3, 3, TREG_SN, 1, + { "addbs_u.sn", TILEPRO_OPC_ADDBS_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addh", TILE_OPC_ADDH, 0x3, 3, TREG_ZERO, 1, + { "addh", TILEPRO_OPC_ADDH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addh.sn", TILE_OPC_ADDH_SN, 0x3, 3, TREG_SN, 1, + { "addh.sn", TILEPRO_OPC_ADDH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addhs", TILE_OPC_ADDHS, 0x3, 3, TREG_ZERO, 1, + { "addhs", TILEPRO_OPC_ADDHS, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addhs.sn", TILE_OPC_ADDHS_SN, 0x3, 3, TREG_SN, 1, + { "addhs.sn", TILEPRO_OPC_ADDHS_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "addi", TILE_OPC_ADDI, 0xf, 3, TREG_ZERO, 1, + { "addi", TILEPRO_OPC_ADDI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, }, - { "addi.sn", TILE_OPC_ADDI_SN, 0x3, 3, TREG_SN, 1, + { "addi.sn", TILEPRO_OPC_ADDI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "addib", TILE_OPC_ADDIB, 0x3, 3, TREG_ZERO, 1, + { "addib", TILEPRO_OPC_ADDIB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "addib.sn", TILE_OPC_ADDIB_SN, 0x3, 3, TREG_SN, 1, + { "addib.sn", TILEPRO_OPC_ADDIB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "addih", TILE_OPC_ADDIH, 0x3, 3, TREG_ZERO, 1, + { "addih", TILEPRO_OPC_ADDIH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "addih.sn", TILE_OPC_ADDIH_SN, 0x3, 3, TREG_SN, 1, + { "addih.sn", TILEPRO_OPC_ADDIH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "addli", TILE_OPC_ADDLI, 0x3, 3, TREG_ZERO, 1, + { "addli", TILEPRO_OPC_ADDLI, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 4 }, { 9, 10, 5 }, { 0, }, { 0, }, { 0, } }, }, - { "addli.sn", TILE_OPC_ADDLI_SN, 0x3, 3, TREG_SN, 1, + { "addli.sn", TILEPRO_OPC_ADDLI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 4 }, { 9, 10, 5 }, { 0, }, { 0, }, { 0, } }, }, - { "addlis", TILE_OPC_ADDLIS, 0x3, 3, TREG_SN, 1, + { "addlis", TILEPRO_OPC_ADDLIS, 0x3, 3, TREG_SN, 1, { { 7, 8, 4 }, { 9, 10, 5 }, { 0, }, { 0, }, { 0, } }, }, - { "adds", TILE_OPC_ADDS, 0x3, 3, TREG_ZERO, 1, + { "adds", TILEPRO_OPC_ADDS, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "adds.sn", TILE_OPC_ADDS_SN, 0x3, 3, TREG_SN, 1, + { "adds.sn", TILEPRO_OPC_ADDS_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "adiffb_u", TILE_OPC_ADIFFB_U, 0x1, 3, TREG_ZERO, 1, + { "adiffb_u", TILEPRO_OPC_ADIFFB_U, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "adiffb_u.sn", TILE_OPC_ADIFFB_U_SN, 0x1, 3, TREG_SN, 1, + { "adiffb_u.sn", TILEPRO_OPC_ADIFFB_U_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "adiffh", TILE_OPC_ADIFFH, 0x1, 3, TREG_ZERO, 1, + { "adiffh", TILEPRO_OPC_ADIFFH, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "adiffh.sn", TILE_OPC_ADIFFH_SN, 0x1, 3, TREG_SN, 1, + { "adiffh.sn", TILEPRO_OPC_ADIFFH_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "and", TILE_OPC_AND, 0xf, 3, TREG_ZERO, 1, + { "and", TILEPRO_OPC_AND, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "and.sn", TILE_OPC_AND_SN, 0x3, 3, TREG_SN, 1, + { "and.sn", TILEPRO_OPC_AND_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "andi", TILE_OPC_ANDI, 0xf, 3, TREG_ZERO, 1, + { "andi", TILEPRO_OPC_ANDI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, }, - { "andi.sn", TILE_OPC_ANDI_SN, 0x3, 3, TREG_SN, 1, + { "andi.sn", TILEPRO_OPC_ANDI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "auli", TILE_OPC_AULI, 0x3, 3, TREG_ZERO, 1, + { "auli", TILEPRO_OPC_AULI, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 4 }, { 9, 10, 5 }, { 0, }, { 0, }, { 0, } }, }, - { "avgb_u", TILE_OPC_AVGB_U, 0x1, 3, TREG_ZERO, 1, + { "avgb_u", TILEPRO_OPC_AVGB_U, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "avgb_u.sn", TILE_OPC_AVGB_U_SN, 0x1, 3, TREG_SN, 1, + { "avgb_u.sn", TILEPRO_OPC_AVGB_U_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "avgh", TILE_OPC_AVGH, 0x1, 3, TREG_ZERO, 1, + { "avgh", TILEPRO_OPC_AVGH, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "avgh.sn", TILE_OPC_AVGH_SN, 0x1, 3, TREG_SN, 1, + { "avgh.sn", TILEPRO_OPC_AVGH_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "bbns", TILE_OPC_BBNS, 0x2, 2, TREG_ZERO, 1, + { "bbns", TILEPRO_OPC_BBNS, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bbns.sn", TILE_OPC_BBNS_SN, 0x2, 2, TREG_SN, 1, + { "bbns.sn", TILEPRO_OPC_BBNS_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bbnst", TILE_OPC_BBNST, 0x2, 2, TREG_ZERO, 1, + { "bbnst", TILEPRO_OPC_BBNST, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bbnst.sn", TILE_OPC_BBNST_SN, 0x2, 2, TREG_SN, 1, + { "bbnst.sn", TILEPRO_OPC_BBNST_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bbs", TILE_OPC_BBS, 0x2, 2, TREG_ZERO, 1, + { "bbs", TILEPRO_OPC_BBS, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bbs.sn", TILE_OPC_BBS_SN, 0x2, 2, TREG_SN, 1, + { "bbs.sn", TILEPRO_OPC_BBS_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bbst", TILE_OPC_BBST, 0x2, 2, TREG_ZERO, 1, + { "bbst", TILEPRO_OPC_BBST, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bbst.sn", TILE_OPC_BBST_SN, 0x2, 2, TREG_SN, 1, + { "bbst.sn", TILEPRO_OPC_BBST_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bgez", TILE_OPC_BGEZ, 0x2, 2, TREG_ZERO, 1, + { "bgez", TILEPRO_OPC_BGEZ, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bgez.sn", TILE_OPC_BGEZ_SN, 0x2, 2, TREG_SN, 1, + { "bgez.sn", TILEPRO_OPC_BGEZ_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bgezt", TILE_OPC_BGEZT, 0x2, 2, TREG_ZERO, 1, + { "bgezt", TILEPRO_OPC_BGEZT, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bgezt.sn", TILE_OPC_BGEZT_SN, 0x2, 2, TREG_SN, 1, + { "bgezt.sn", TILEPRO_OPC_BGEZT_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bgz", TILE_OPC_BGZ, 0x2, 2, TREG_ZERO, 1, + { "bgz", TILEPRO_OPC_BGZ, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bgz.sn", TILE_OPC_BGZ_SN, 0x2, 2, TREG_SN, 1, + { "bgz.sn", TILEPRO_OPC_BGZ_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bgzt", TILE_OPC_BGZT, 0x2, 2, TREG_ZERO, 1, + { "bgzt", TILEPRO_OPC_BGZT, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bgzt.sn", TILE_OPC_BGZT_SN, 0x2, 2, TREG_SN, 1, + { "bgzt.sn", TILEPRO_OPC_BGZT_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bitx", TILE_OPC_BITX, 0x5, 2, TREG_ZERO, 1, + { "bitx", TILEPRO_OPC_BITX, 0x5, 2, TREG_ZERO, 1, { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, }, - { "bitx.sn", TILE_OPC_BITX_SN, 0x1, 2, TREG_SN, 1, + { "bitx.sn", TILEPRO_OPC_BITX_SN, 0x1, 2, TREG_SN, 1, { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "blez", TILE_OPC_BLEZ, 0x2, 2, TREG_ZERO, 1, + { "blez", TILEPRO_OPC_BLEZ, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "blez.sn", TILE_OPC_BLEZ_SN, 0x2, 2, TREG_SN, 1, + { "blez.sn", TILEPRO_OPC_BLEZ_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "blezt", TILE_OPC_BLEZT, 0x2, 2, TREG_ZERO, 1, + { "blezt", TILEPRO_OPC_BLEZT, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "blezt.sn", TILE_OPC_BLEZT_SN, 0x2, 2, TREG_SN, 1, + { "blezt.sn", TILEPRO_OPC_BLEZT_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "blz", TILE_OPC_BLZ, 0x2, 2, TREG_ZERO, 1, + { "blz", TILEPRO_OPC_BLZ, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "blz.sn", TILE_OPC_BLZ_SN, 0x2, 2, TREG_SN, 1, + { "blz.sn", TILEPRO_OPC_BLZ_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "blzt", TILE_OPC_BLZT, 0x2, 2, TREG_ZERO, 1, + { "blzt", TILEPRO_OPC_BLZT, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "blzt.sn", TILE_OPC_BLZT_SN, 0x2, 2, TREG_SN, 1, + { "blzt.sn", TILEPRO_OPC_BLZT_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bnz", TILE_OPC_BNZ, 0x2, 2, TREG_ZERO, 1, + { "bnz", TILEPRO_OPC_BNZ, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bnz.sn", TILE_OPC_BNZ_SN, 0x2, 2, TREG_SN, 1, + { "bnz.sn", TILEPRO_OPC_BNZ_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bnzt", TILE_OPC_BNZT, 0x2, 2, TREG_ZERO, 1, + { "bnzt", TILEPRO_OPC_BNZT, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bnzt.sn", TILE_OPC_BNZT_SN, 0x2, 2, TREG_SN, 1, + { "bnzt.sn", TILEPRO_OPC_BNZT_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bytex", TILE_OPC_BYTEX, 0x5, 2, TREG_ZERO, 1, + { "bytex", TILEPRO_OPC_BYTEX, 0x5, 2, TREG_ZERO, 1, { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, }, - { "bytex.sn", TILE_OPC_BYTEX_SN, 0x1, 2, TREG_SN, 1, + { "bytex.sn", TILEPRO_OPC_BYTEX_SN, 0x1, 2, TREG_SN, 1, { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "bz", TILE_OPC_BZ, 0x2, 2, TREG_ZERO, 1, + { "bz", TILEPRO_OPC_BZ, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bz.sn", TILE_OPC_BZ_SN, 0x2, 2, TREG_SN, 1, + { "bz.sn", TILEPRO_OPC_BZ_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bzt", TILE_OPC_BZT, 0x2, 2, TREG_ZERO, 1, + { "bzt", TILEPRO_OPC_BZT, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "bzt.sn", TILE_OPC_BZT_SN, 0x2, 2, TREG_SN, 1, + { "bzt.sn", TILEPRO_OPC_BZT_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, }, - { "clz", TILE_OPC_CLZ, 0x5, 2, TREG_ZERO, 1, + { "clz", TILEPRO_OPC_CLZ, 0x5, 2, TREG_ZERO, 1, { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, }, - { "clz.sn", TILE_OPC_CLZ_SN, 0x1, 2, TREG_SN, 1, + { "clz.sn", TILEPRO_OPC_CLZ_SN, 0x1, 2, TREG_SN, 1, { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "crc32_32", TILE_OPC_CRC32_32, 0x1, 3, TREG_ZERO, 1, + { "crc32_32", TILEPRO_OPC_CRC32_32, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "crc32_32.sn", TILE_OPC_CRC32_32_SN, 0x1, 3, TREG_SN, 1, + { "crc32_32.sn", TILEPRO_OPC_CRC32_32_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "crc32_8", TILE_OPC_CRC32_8, 0x1, 3, TREG_ZERO, 1, + { "crc32_8", TILEPRO_OPC_CRC32_8, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "crc32_8.sn", TILE_OPC_CRC32_8_SN, 0x1, 3, TREG_SN, 1, + { "crc32_8.sn", TILEPRO_OPC_CRC32_8_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "ctz", TILE_OPC_CTZ, 0x5, 2, TREG_ZERO, 1, + { "ctz", TILEPRO_OPC_CTZ, 0x5, 2, TREG_ZERO, 1, { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, }, - { "ctz.sn", TILE_OPC_CTZ_SN, 0x1, 2, TREG_SN, 1, + { "ctz.sn", TILEPRO_OPC_CTZ_SN, 0x1, 2, TREG_SN, 1, { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "drain", TILE_OPC_DRAIN, 0x2, 0, TREG_ZERO, 0, + { "drain", TILEPRO_OPC_DRAIN, 0x2, 0, TREG_ZERO, 0, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "dtlbpr", TILE_OPC_DTLBPR, 0x2, 1, TREG_ZERO, 1, + { "dtlbpr", TILEPRO_OPC_DTLBPR, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "dword_align", TILE_OPC_DWORD_ALIGN, 0x1, 3, TREG_ZERO, 1, + { "dword_align", TILEPRO_OPC_DWORD_ALIGN, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "dword_align.sn", TILE_OPC_DWORD_ALIGN_SN, 0x1, 3, TREG_SN, 1, + { "dword_align.sn", TILEPRO_OPC_DWORD_ALIGN_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "finv", TILE_OPC_FINV, 0x2, 1, TREG_ZERO, 1, + { "finv", TILEPRO_OPC_FINV, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "flush", TILE_OPC_FLUSH, 0x2, 1, TREG_ZERO, 1, + { "flush", TILEPRO_OPC_FLUSH, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "fnop", TILE_OPC_FNOP, 0xf, 0, TREG_ZERO, 1, + { "fnop", TILEPRO_OPC_FNOP, 0xf, 0, TREG_ZERO, 1, { { }, { }, { }, { }, { 0, } }, }, - { "icoh", TILE_OPC_ICOH, 0x2, 1, TREG_ZERO, 1, + { "icoh", TILEPRO_OPC_ICOH, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "ill", TILE_OPC_ILL, 0xa, 0, TREG_ZERO, 1, + { "ill", TILEPRO_OPC_ILL, 0xa, 0, TREG_ZERO, 1, { { 0, }, { }, { 0, }, { }, { 0, } }, }, - { "inthb", TILE_OPC_INTHB, 0x3, 3, TREG_ZERO, 1, + { "inthb", TILEPRO_OPC_INTHB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "inthb.sn", TILE_OPC_INTHB_SN, 0x3, 3, TREG_SN, 1, + { "inthb.sn", TILEPRO_OPC_INTHB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "inthh", TILE_OPC_INTHH, 0x3, 3, TREG_ZERO, 1, + { "inthh", TILEPRO_OPC_INTHH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "inthh.sn", TILE_OPC_INTHH_SN, 0x3, 3, TREG_SN, 1, + { "inthh.sn", TILEPRO_OPC_INTHH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "intlb", TILE_OPC_INTLB, 0x3, 3, TREG_ZERO, 1, + { "intlb", TILEPRO_OPC_INTLB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "intlb.sn", TILE_OPC_INTLB_SN, 0x3, 3, TREG_SN, 1, + { "intlb.sn", TILEPRO_OPC_INTLB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "intlh", TILE_OPC_INTLH, 0x3, 3, TREG_ZERO, 1, + { "intlh", TILEPRO_OPC_INTLH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "intlh.sn", TILE_OPC_INTLH_SN, 0x3, 3, TREG_SN, 1, + { "intlh.sn", TILEPRO_OPC_INTLH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "inv", TILE_OPC_INV, 0x2, 1, TREG_ZERO, 1, + { "inv", TILEPRO_OPC_INV, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "iret", TILE_OPC_IRET, 0x2, 0, TREG_ZERO, 1, + { "iret", TILEPRO_OPC_IRET, 0x2, 0, TREG_ZERO, 1, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "jalb", TILE_OPC_JALB, 0x2, 1, TREG_LR, 1, + { "jalb", TILEPRO_OPC_JALB, 0x2, 1, TREG_LR, 1, { { 0, }, { 22 }, { 0, }, { 0, }, { 0, } }, }, - { "jalf", TILE_OPC_JALF, 0x2, 1, TREG_LR, 1, + { "jalf", TILEPRO_OPC_JALF, 0x2, 1, TREG_LR, 1, { { 0, }, { 22 }, { 0, }, { 0, }, { 0, } }, }, - { "jalr", TILE_OPC_JALR, 0x2, 1, TREG_LR, 1, + { "jalr", TILEPRO_OPC_JALR, 0x2, 1, TREG_LR, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "jalrp", TILE_OPC_JALRP, 0x2, 1, TREG_LR, 1, + { "jalrp", TILEPRO_OPC_JALRP, 0x2, 1, TREG_LR, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "jb", TILE_OPC_JB, 0x2, 1, TREG_ZERO, 1, + { "jb", TILEPRO_OPC_JB, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 22 }, { 0, }, { 0, }, { 0, } }, }, - { "jf", TILE_OPC_JF, 0x2, 1, TREG_ZERO, 1, + { "jf", TILEPRO_OPC_JF, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 22 }, { 0, }, { 0, }, { 0, } }, }, - { "jr", TILE_OPC_JR, 0x2, 1, TREG_ZERO, 1, + { "jr", TILEPRO_OPC_JR, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "jrp", TILE_OPC_JRP, 0x2, 1, TREG_ZERO, 1, + { "jrp", TILEPRO_OPC_JRP, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "lb", TILE_OPC_LB, 0x12, 2, TREG_ZERO, 1, + { "lb", TILEPRO_OPC_LB, 0x12, 2, TREG_ZERO, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, }, - { "lb.sn", TILE_OPC_LB_SN, 0x2, 2, TREG_SN, 1, + { "lb.sn", TILEPRO_OPC_LB_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "lb_u", TILE_OPC_LB_U, 0x12, 2, TREG_ZERO, 1, + { "lb_u", TILEPRO_OPC_LB_U, 0x12, 2, TREG_ZERO, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, }, - { "lb_u.sn", TILE_OPC_LB_U_SN, 0x2, 2, TREG_SN, 1, + { "lb_u.sn", TILEPRO_OPC_LB_U_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "lbadd", TILE_OPC_LBADD, 0x2, 3, TREG_ZERO, 1, + { "lbadd", TILEPRO_OPC_LBADD, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lbadd.sn", TILE_OPC_LBADD_SN, 0x2, 3, TREG_SN, 1, + { "lbadd.sn", TILEPRO_OPC_LBADD_SN, 0x2, 3, TREG_SN, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lbadd_u", TILE_OPC_LBADD_U, 0x2, 3, TREG_ZERO, 1, + { "lbadd_u", TILEPRO_OPC_LBADD_U, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lbadd_u.sn", TILE_OPC_LBADD_U_SN, 0x2, 3, TREG_SN, 1, + { "lbadd_u.sn", TILEPRO_OPC_LBADD_U_SN, 0x2, 3, TREG_SN, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lh", TILE_OPC_LH, 0x12, 2, TREG_ZERO, 1, + { "lh", TILEPRO_OPC_LH, 0x12, 2, TREG_ZERO, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, }, - { "lh.sn", TILE_OPC_LH_SN, 0x2, 2, TREG_SN, 1, + { "lh.sn", TILEPRO_OPC_LH_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "lh_u", TILE_OPC_LH_U, 0x12, 2, TREG_ZERO, 1, + { "lh_u", TILEPRO_OPC_LH_U, 0x12, 2, TREG_ZERO, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, }, - { "lh_u.sn", TILE_OPC_LH_U_SN, 0x2, 2, TREG_SN, 1, + { "lh_u.sn", TILEPRO_OPC_LH_U_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "lhadd", TILE_OPC_LHADD, 0x2, 3, TREG_ZERO, 1, + { "lhadd", TILEPRO_OPC_LHADD, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lhadd.sn", TILE_OPC_LHADD_SN, 0x2, 3, TREG_SN, 1, + { "lhadd.sn", TILEPRO_OPC_LHADD_SN, 0x2, 3, TREG_SN, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lhadd_u", TILE_OPC_LHADD_U, 0x2, 3, TREG_ZERO, 1, + { "lhadd_u", TILEPRO_OPC_LHADD_U, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lhadd_u.sn", TILE_OPC_LHADD_U_SN, 0x2, 3, TREG_SN, 1, + { "lhadd_u.sn", TILEPRO_OPC_LHADD_U_SN, 0x2, 3, TREG_SN, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lnk", TILE_OPC_LNK, 0x2, 1, TREG_ZERO, 1, + { "lnk", TILEPRO_OPC_LNK, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, }, - { "lnk.sn", TILE_OPC_LNK_SN, 0x2, 1, TREG_SN, 1, + { "lnk.sn", TILEPRO_OPC_LNK_SN, 0x2, 1, TREG_SN, 1, { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, }, - { "lw", TILE_OPC_LW, 0x12, 2, TREG_ZERO, 1, + { "lw", TILEPRO_OPC_LW, 0x12, 2, TREG_ZERO, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, }, - { "lw.sn", TILE_OPC_LW_SN, 0x2, 2, TREG_SN, 1, + { "lw.sn", TILEPRO_OPC_LW_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "lw_na", TILE_OPC_LW_NA, 0x2, 2, TREG_ZERO, 1, + { "lw_na", TILEPRO_OPC_LW_NA, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "lw_na.sn", TILE_OPC_LW_NA_SN, 0x2, 2, TREG_SN, 1, + { "lw_na.sn", TILEPRO_OPC_LW_NA_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "lwadd", TILE_OPC_LWADD, 0x2, 3, TREG_ZERO, 1, + { "lwadd", TILEPRO_OPC_LWADD, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lwadd.sn", TILE_OPC_LWADD_SN, 0x2, 3, TREG_SN, 1, + { "lwadd.sn", TILEPRO_OPC_LWADD_SN, 0x2, 3, TREG_SN, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lwadd_na", TILE_OPC_LWADD_NA, 0x2, 3, TREG_ZERO, 1, + { "lwadd_na", TILEPRO_OPC_LWADD_NA, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "lwadd_na.sn", TILE_OPC_LWADD_NA_SN, 0x2, 3, TREG_SN, 1, + { "lwadd_na.sn", TILEPRO_OPC_LWADD_NA_SN, 0x2, 3, TREG_SN, 1, { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "maxb_u", TILE_OPC_MAXB_U, 0x3, 3, TREG_ZERO, 1, + { "maxb_u", TILEPRO_OPC_MAXB_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "maxb_u.sn", TILE_OPC_MAXB_U_SN, 0x3, 3, TREG_SN, 1, + { "maxb_u.sn", TILEPRO_OPC_MAXB_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "maxh", TILE_OPC_MAXH, 0x3, 3, TREG_ZERO, 1, + { "maxh", TILEPRO_OPC_MAXH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "maxh.sn", TILE_OPC_MAXH_SN, 0x3, 3, TREG_SN, 1, + { "maxh.sn", TILEPRO_OPC_MAXH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "maxib_u", TILE_OPC_MAXIB_U, 0x3, 3, TREG_ZERO, 1, + { "maxib_u", TILEPRO_OPC_MAXIB_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "maxib_u.sn", TILE_OPC_MAXIB_U_SN, 0x3, 3, TREG_SN, 1, + { "maxib_u.sn", TILEPRO_OPC_MAXIB_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "maxih", TILE_OPC_MAXIH, 0x3, 3, TREG_ZERO, 1, + { "maxih", TILEPRO_OPC_MAXIH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "maxih.sn", TILE_OPC_MAXIH_SN, 0x3, 3, TREG_SN, 1, + { "maxih.sn", TILEPRO_OPC_MAXIH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "mf", TILE_OPC_MF, 0x2, 0, TREG_ZERO, 1, + { "mf", TILEPRO_OPC_MF, 0x2, 0, TREG_ZERO, 1, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "mfspr", TILE_OPC_MFSPR, 0x2, 2, TREG_ZERO, 1, + { "mfspr", TILEPRO_OPC_MFSPR, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 9, 25 }, { 0, }, { 0, }, { 0, } }, }, - { "minb_u", TILE_OPC_MINB_U, 0x3, 3, TREG_ZERO, 1, + { "minb_u", TILEPRO_OPC_MINB_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "minb_u.sn", TILE_OPC_MINB_U_SN, 0x3, 3, TREG_SN, 1, + { "minb_u.sn", TILEPRO_OPC_MINB_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "minh", TILE_OPC_MINH, 0x3, 3, TREG_ZERO, 1, + { "minh", TILEPRO_OPC_MINH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "minh.sn", TILE_OPC_MINH_SN, 0x3, 3, TREG_SN, 1, + { "minh.sn", TILEPRO_OPC_MINH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "minib_u", TILE_OPC_MINIB_U, 0x3, 3, TREG_ZERO, 1, + { "minib_u", TILEPRO_OPC_MINIB_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "minib_u.sn", TILE_OPC_MINIB_U_SN, 0x3, 3, TREG_SN, 1, + { "minib_u.sn", TILEPRO_OPC_MINIB_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "minih", TILE_OPC_MINIH, 0x3, 3, TREG_ZERO, 1, + { "minih", TILEPRO_OPC_MINIH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "minih.sn", TILE_OPC_MINIH_SN, 0x3, 3, TREG_SN, 1, + { "minih.sn", TILEPRO_OPC_MINIH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "mm", TILE_OPC_MM, 0x3, 5, TREG_ZERO, 1, + { "mm", TILEPRO_OPC_MM, 0x3, 5, TREG_ZERO, 1, { { 7, 8, 16, 26, 27 }, { 9, 10, 17, 28, 29 }, { 0, }, { 0, }, { 0, } }, }, - { "mnz", TILE_OPC_MNZ, 0xf, 3, TREG_ZERO, 1, + { "mnz", TILEPRO_OPC_MNZ, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "mnz.sn", TILE_OPC_MNZ_SN, 0x3, 3, TREG_SN, 1, + { "mnz.sn", TILEPRO_OPC_MNZ_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mnzb", TILE_OPC_MNZB, 0x3, 3, TREG_ZERO, 1, + { "mnzb", TILEPRO_OPC_MNZB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mnzb.sn", TILE_OPC_MNZB_SN, 0x3, 3, TREG_SN, 1, + { "mnzb.sn", TILEPRO_OPC_MNZB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mnzh", TILE_OPC_MNZH, 0x3, 3, TREG_ZERO, 1, + { "mnzh", TILEPRO_OPC_MNZH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mnzh.sn", TILE_OPC_MNZH_SN, 0x3, 3, TREG_SN, 1, + { "mnzh.sn", TILEPRO_OPC_MNZH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mtspr", TILE_OPC_MTSPR, 0x2, 2, TREG_ZERO, 1, + { "mtspr", TILEPRO_OPC_MTSPR, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 30, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "mulhh_ss", TILE_OPC_MULHH_SS, 0x5, 3, TREG_ZERO, 1, + { "mulhh_ss", TILEPRO_OPC_MULHH_SS, 0x5, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 11, 12, 18 }, { 0, }, { 0, } }, }, - { "mulhh_ss.sn", TILE_OPC_MULHH_SS_SN, 0x1, 3, TREG_SN, 1, + { "mulhh_ss.sn", TILEPRO_OPC_MULHH_SS_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhh_su", TILE_OPC_MULHH_SU, 0x1, 3, TREG_ZERO, 1, + { "mulhh_su", TILEPRO_OPC_MULHH_SU, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhh_su.sn", TILE_OPC_MULHH_SU_SN, 0x1, 3, TREG_SN, 1, + { "mulhh_su.sn", TILEPRO_OPC_MULHH_SU_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhh_uu", TILE_OPC_MULHH_UU, 0x5, 3, TREG_ZERO, 1, + { "mulhh_uu", TILEPRO_OPC_MULHH_UU, 0x5, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 11, 12, 18 }, { 0, }, { 0, } }, }, - { "mulhh_uu.sn", TILE_OPC_MULHH_UU_SN, 0x1, 3, TREG_SN, 1, + { "mulhh_uu.sn", TILEPRO_OPC_MULHH_UU_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhha_ss", TILE_OPC_MULHHA_SS, 0x5, 3, TREG_ZERO, 1, + { "mulhha_ss", TILEPRO_OPC_MULHHA_SS, 0x5, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, }, - { "mulhha_ss.sn", TILE_OPC_MULHHA_SS_SN, 0x1, 3, TREG_SN, 1, + { "mulhha_ss.sn", TILEPRO_OPC_MULHHA_SS_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhha_su", TILE_OPC_MULHHA_SU, 0x1, 3, TREG_ZERO, 1, + { "mulhha_su", TILEPRO_OPC_MULHHA_SU, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhha_su.sn", TILE_OPC_MULHHA_SU_SN, 0x1, 3, TREG_SN, 1, + { "mulhha_su.sn", TILEPRO_OPC_MULHHA_SU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhha_uu", TILE_OPC_MULHHA_UU, 0x5, 3, TREG_ZERO, 1, + { "mulhha_uu", TILEPRO_OPC_MULHHA_UU, 0x5, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, }, - { "mulhha_uu.sn", TILE_OPC_MULHHA_UU_SN, 0x1, 3, TREG_SN, 1, + { "mulhha_uu.sn", TILEPRO_OPC_MULHHA_UU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhhsa_uu", TILE_OPC_MULHHSA_UU, 0x1, 3, TREG_ZERO, 1, + { "mulhhsa_uu", TILEPRO_OPC_MULHHSA_UU, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhhsa_uu.sn", TILE_OPC_MULHHSA_UU_SN, 0x1, 3, TREG_SN, 1, + { "mulhhsa_uu.sn", TILEPRO_OPC_MULHHSA_UU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhl_ss", TILE_OPC_MULHL_SS, 0x1, 3, TREG_ZERO, 1, + { "mulhl_ss", TILEPRO_OPC_MULHL_SS, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhl_ss.sn", TILE_OPC_MULHL_SS_SN, 0x1, 3, TREG_SN, 1, + { "mulhl_ss.sn", TILEPRO_OPC_MULHL_SS_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhl_su", TILE_OPC_MULHL_SU, 0x1, 3, TREG_ZERO, 1, + { "mulhl_su", TILEPRO_OPC_MULHL_SU, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhl_su.sn", TILE_OPC_MULHL_SU_SN, 0x1, 3, TREG_SN, 1, + { "mulhl_su.sn", TILEPRO_OPC_MULHL_SU_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhl_us", TILE_OPC_MULHL_US, 0x1, 3, TREG_ZERO, 1, + { "mulhl_us", TILEPRO_OPC_MULHL_US, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhl_us.sn", TILE_OPC_MULHL_US_SN, 0x1, 3, TREG_SN, 1, + { "mulhl_us.sn", TILEPRO_OPC_MULHL_US_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhl_uu", TILE_OPC_MULHL_UU, 0x1, 3, TREG_ZERO, 1, + { "mulhl_uu", TILEPRO_OPC_MULHL_UU, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhl_uu.sn", TILE_OPC_MULHL_UU_SN, 0x1, 3, TREG_SN, 1, + { "mulhl_uu.sn", TILEPRO_OPC_MULHL_UU_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhla_ss", TILE_OPC_MULHLA_SS, 0x1, 3, TREG_ZERO, 1, + { "mulhla_ss", TILEPRO_OPC_MULHLA_SS, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhla_ss.sn", TILE_OPC_MULHLA_SS_SN, 0x1, 3, TREG_SN, 1, + { "mulhla_ss.sn", TILEPRO_OPC_MULHLA_SS_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhla_su", TILE_OPC_MULHLA_SU, 0x1, 3, TREG_ZERO, 1, + { "mulhla_su", TILEPRO_OPC_MULHLA_SU, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhla_su.sn", TILE_OPC_MULHLA_SU_SN, 0x1, 3, TREG_SN, 1, + { "mulhla_su.sn", TILEPRO_OPC_MULHLA_SU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhla_us", TILE_OPC_MULHLA_US, 0x1, 3, TREG_ZERO, 1, + { "mulhla_us", TILEPRO_OPC_MULHLA_US, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhla_us.sn", TILE_OPC_MULHLA_US_SN, 0x1, 3, TREG_SN, 1, + { "mulhla_us.sn", TILEPRO_OPC_MULHLA_US_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhla_uu", TILE_OPC_MULHLA_UU, 0x1, 3, TREG_ZERO, 1, + { "mulhla_uu", TILEPRO_OPC_MULHLA_UU, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhla_uu.sn", TILE_OPC_MULHLA_UU_SN, 0x1, 3, TREG_SN, 1, + { "mulhla_uu.sn", TILEPRO_OPC_MULHLA_UU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulhlsa_uu", TILE_OPC_MULHLSA_UU, 0x5, 3, TREG_ZERO, 1, + { "mulhlsa_uu", TILEPRO_OPC_MULHLSA_UU, 0x5, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, }, - { "mulhlsa_uu.sn", TILE_OPC_MULHLSA_UU_SN, 0x1, 3, TREG_SN, 1, + { "mulhlsa_uu.sn", TILEPRO_OPC_MULHLSA_UU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulll_ss", TILE_OPC_MULLL_SS, 0x5, 3, TREG_ZERO, 1, + { "mulll_ss", TILEPRO_OPC_MULLL_SS, 0x5, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 11, 12, 18 }, { 0, }, { 0, } }, }, - { "mulll_ss.sn", TILE_OPC_MULLL_SS_SN, 0x1, 3, TREG_SN, 1, + { "mulll_ss.sn", TILEPRO_OPC_MULLL_SS_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulll_su", TILE_OPC_MULLL_SU, 0x1, 3, TREG_ZERO, 1, + { "mulll_su", TILEPRO_OPC_MULLL_SU, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulll_su.sn", TILE_OPC_MULLL_SU_SN, 0x1, 3, TREG_SN, 1, + { "mulll_su.sn", TILEPRO_OPC_MULLL_SU_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulll_uu", TILE_OPC_MULLL_UU, 0x5, 3, TREG_ZERO, 1, + { "mulll_uu", TILEPRO_OPC_MULLL_UU, 0x5, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 11, 12, 18 }, { 0, }, { 0, } }, }, - { "mulll_uu.sn", TILE_OPC_MULLL_UU_SN, 0x1, 3, TREG_SN, 1, + { "mulll_uu.sn", TILEPRO_OPC_MULLL_UU_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mullla_ss", TILE_OPC_MULLLA_SS, 0x5, 3, TREG_ZERO, 1, + { "mullla_ss", TILEPRO_OPC_MULLLA_SS, 0x5, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, }, - { "mullla_ss.sn", TILE_OPC_MULLLA_SS_SN, 0x1, 3, TREG_SN, 1, + { "mullla_ss.sn", TILEPRO_OPC_MULLLA_SS_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mullla_su", TILE_OPC_MULLLA_SU, 0x1, 3, TREG_ZERO, 1, + { "mullla_su", TILEPRO_OPC_MULLLA_SU, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mullla_su.sn", TILE_OPC_MULLLA_SU_SN, 0x1, 3, TREG_SN, 1, + { "mullla_su.sn", TILEPRO_OPC_MULLLA_SU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mullla_uu", TILE_OPC_MULLLA_UU, 0x5, 3, TREG_ZERO, 1, + { "mullla_uu", TILEPRO_OPC_MULLLA_UU, 0x5, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, }, - { "mullla_uu.sn", TILE_OPC_MULLLA_UU_SN, 0x1, 3, TREG_SN, 1, + { "mullla_uu.sn", TILEPRO_OPC_MULLLA_UU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulllsa_uu", TILE_OPC_MULLLSA_UU, 0x1, 3, TREG_ZERO, 1, + { "mulllsa_uu", TILEPRO_OPC_MULLLSA_UU, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mulllsa_uu.sn", TILE_OPC_MULLLSA_UU_SN, 0x1, 3, TREG_SN, 1, + { "mulllsa_uu.sn", TILEPRO_OPC_MULLLSA_UU_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mvnz", TILE_OPC_MVNZ, 0x5, 3, TREG_ZERO, 1, + { "mvnz", TILEPRO_OPC_MVNZ, 0x5, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, }, - { "mvnz.sn", TILE_OPC_MVNZ_SN, 0x1, 3, TREG_SN, 1, + { "mvnz.sn", TILEPRO_OPC_MVNZ_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mvz", TILE_OPC_MVZ, 0x5, 3, TREG_ZERO, 1, + { "mvz", TILEPRO_OPC_MVZ, 0x5, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, }, - { "mvz.sn", TILE_OPC_MVZ_SN, 0x1, 3, TREG_SN, 1, + { "mvz.sn", TILEPRO_OPC_MVZ_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "mz", TILE_OPC_MZ, 0xf, 3, TREG_ZERO, 1, + { "mz", TILEPRO_OPC_MZ, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "mz.sn", TILE_OPC_MZ_SN, 0x3, 3, TREG_SN, 1, + { "mz.sn", TILEPRO_OPC_MZ_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mzb", TILE_OPC_MZB, 0x3, 3, TREG_ZERO, 1, + { "mzb", TILEPRO_OPC_MZB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mzb.sn", TILE_OPC_MZB_SN, 0x3, 3, TREG_SN, 1, + { "mzb.sn", TILEPRO_OPC_MZB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mzh", TILE_OPC_MZH, 0x3, 3, TREG_ZERO, 1, + { "mzh", TILEPRO_OPC_MZH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "mzh.sn", TILE_OPC_MZH_SN, 0x3, 3, TREG_SN, 1, + { "mzh.sn", TILEPRO_OPC_MZH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "nap", TILE_OPC_NAP, 0x2, 0, TREG_ZERO, 0, + { "nap", TILEPRO_OPC_NAP, 0x2, 0, TREG_ZERO, 0, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "nop", TILE_OPC_NOP, 0xf, 0, TREG_ZERO, 1, + { "nop", TILEPRO_OPC_NOP, 0xf, 0, TREG_ZERO, 1, { { }, { }, { }, { }, { 0, } }, }, - { "nor", TILE_OPC_NOR, 0xf, 3, TREG_ZERO, 1, + { "nor", TILEPRO_OPC_NOR, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "nor.sn", TILE_OPC_NOR_SN, 0x3, 3, TREG_SN, 1, + { "nor.sn", TILEPRO_OPC_NOR_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "or", TILE_OPC_OR, 0xf, 3, TREG_ZERO, 1, + { "or", TILEPRO_OPC_OR, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "or.sn", TILE_OPC_OR_SN, 0x3, 3, TREG_SN, 1, + { "or.sn", TILEPRO_OPC_OR_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "ori", TILE_OPC_ORI, 0xf, 3, TREG_ZERO, 1, + { "ori", TILEPRO_OPC_ORI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, }, - { "ori.sn", TILE_OPC_ORI_SN, 0x3, 3, TREG_SN, 1, + { "ori.sn", TILEPRO_OPC_ORI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "packbs_u", TILE_OPC_PACKBS_U, 0x3, 3, TREG_ZERO, 1, + { "packbs_u", TILEPRO_OPC_PACKBS_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "packbs_u.sn", TILE_OPC_PACKBS_U_SN, 0x3, 3, TREG_SN, 1, + { "packbs_u.sn", TILEPRO_OPC_PACKBS_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "packhb", TILE_OPC_PACKHB, 0x3, 3, TREG_ZERO, 1, + { "packhb", TILEPRO_OPC_PACKHB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "packhb.sn", TILE_OPC_PACKHB_SN, 0x3, 3, TREG_SN, 1, + { "packhb.sn", TILEPRO_OPC_PACKHB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "packhs", TILE_OPC_PACKHS, 0x3, 3, TREG_ZERO, 1, + { "packhs", TILEPRO_OPC_PACKHS, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "packhs.sn", TILE_OPC_PACKHS_SN, 0x3, 3, TREG_SN, 1, + { "packhs.sn", TILEPRO_OPC_PACKHS_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "packlb", TILE_OPC_PACKLB, 0x3, 3, TREG_ZERO, 1, + { "packlb", TILEPRO_OPC_PACKLB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "packlb.sn", TILE_OPC_PACKLB_SN, 0x3, 3, TREG_SN, 1, + { "packlb.sn", TILEPRO_OPC_PACKLB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "pcnt", TILE_OPC_PCNT, 0x5, 2, TREG_ZERO, 1, + { "pcnt", TILEPRO_OPC_PCNT, 0x5, 2, TREG_ZERO, 1, { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, }, - { "pcnt.sn", TILE_OPC_PCNT_SN, 0x1, 2, TREG_SN, 1, + { "pcnt.sn", TILEPRO_OPC_PCNT_SN, 0x1, 2, TREG_SN, 1, { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "rl", TILE_OPC_RL, 0xf, 3, TREG_ZERO, 1, + { "rl", TILEPRO_OPC_RL, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "rl.sn", TILE_OPC_RL_SN, 0x3, 3, TREG_SN, 1, + { "rl.sn", TILEPRO_OPC_RL_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "rli", TILE_OPC_RLI, 0xf, 3, TREG_ZERO, 1, + { "rli", TILEPRO_OPC_RLI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 11, 12, 34 }, { 13, 14, 35 }, { 0, } }, }, - { "rli.sn", TILE_OPC_RLI_SN, 0x3, 3, TREG_SN, 1, + { "rli.sn", TILEPRO_OPC_RLI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "s1a", TILE_OPC_S1A, 0xf, 3, TREG_ZERO, 1, + { "s1a", TILEPRO_OPC_S1A, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "s1a.sn", TILE_OPC_S1A_SN, 0x3, 3, TREG_SN, 1, + { "s1a.sn", TILEPRO_OPC_S1A_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "s2a", TILE_OPC_S2A, 0xf, 3, TREG_ZERO, 1, + { "s2a", TILEPRO_OPC_S2A, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "s2a.sn", TILE_OPC_S2A_SN, 0x3, 3, TREG_SN, 1, + { "s2a.sn", TILEPRO_OPC_S2A_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "s3a", TILE_OPC_S3A, 0xf, 3, TREG_ZERO, 1, + { "s3a", TILEPRO_OPC_S3A, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "s3a.sn", TILE_OPC_S3A_SN, 0x3, 3, TREG_SN, 1, + { "s3a.sn", TILEPRO_OPC_S3A_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sadab_u", TILE_OPC_SADAB_U, 0x1, 3, TREG_ZERO, 1, + { "sadab_u", TILEPRO_OPC_SADAB_U, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadab_u.sn", TILE_OPC_SADAB_U_SN, 0x1, 3, TREG_SN, 1, + { "sadab_u.sn", TILEPRO_OPC_SADAB_U_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadah", TILE_OPC_SADAH, 0x1, 3, TREG_ZERO, 1, + { "sadah", TILEPRO_OPC_SADAH, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadah.sn", TILE_OPC_SADAH_SN, 0x1, 3, TREG_SN, 1, + { "sadah.sn", TILEPRO_OPC_SADAH_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadah_u", TILE_OPC_SADAH_U, 0x1, 3, TREG_ZERO, 1, + { "sadah_u", TILEPRO_OPC_SADAH_U, 0x1, 3, TREG_ZERO, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadah_u.sn", TILE_OPC_SADAH_U_SN, 0x1, 3, TREG_SN, 1, + { "sadah_u.sn", TILEPRO_OPC_SADAH_U_SN, 0x1, 3, TREG_SN, 1, { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadb_u", TILE_OPC_SADB_U, 0x1, 3, TREG_ZERO, 1, + { "sadb_u", TILEPRO_OPC_SADB_U, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadb_u.sn", TILE_OPC_SADB_U_SN, 0x1, 3, TREG_SN, 1, + { "sadb_u.sn", TILEPRO_OPC_SADB_U_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadh", TILE_OPC_SADH, 0x1, 3, TREG_ZERO, 1, + { "sadh", TILEPRO_OPC_SADH, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadh.sn", TILE_OPC_SADH_SN, 0x1, 3, TREG_SN, 1, + { "sadh.sn", TILEPRO_OPC_SADH_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadh_u", TILE_OPC_SADH_U, 0x1, 3, TREG_ZERO, 1, + { "sadh_u", TILEPRO_OPC_SADH_U, 0x1, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sadh_u.sn", TILE_OPC_SADH_U_SN, 0x1, 3, TREG_SN, 1, + { "sadh_u.sn", TILEPRO_OPC_SADH_U_SN, 0x1, 3, TREG_SN, 1, { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "sb", TILE_OPC_SB, 0x12, 2, TREG_ZERO, 1, + { "sb", TILEPRO_OPC_SB, 0x12, 2, TREG_ZERO, 1, { { 0, }, { 10, 17 }, { 0, }, { 0, }, { 15, 36 } }, }, - { "sbadd", TILE_OPC_SBADD, 0x2, 3, TREG_ZERO, 1, + { "sbadd", TILEPRO_OPC_SBADD, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 24, 17, 37 }, { 0, }, { 0, }, { 0, } }, }, - { "seq", TILE_OPC_SEQ, 0xf, 3, TREG_ZERO, 1, + { "seq", TILEPRO_OPC_SEQ, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "seq.sn", TILE_OPC_SEQ_SN, 0x3, 3, TREG_SN, 1, + { "seq.sn", TILEPRO_OPC_SEQ_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "seqb", TILE_OPC_SEQB, 0x3, 3, TREG_ZERO, 1, + { "seqb", TILEPRO_OPC_SEQB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "seqb.sn", TILE_OPC_SEQB_SN, 0x3, 3, TREG_SN, 1, + { "seqb.sn", TILEPRO_OPC_SEQB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "seqh", TILE_OPC_SEQH, 0x3, 3, TREG_ZERO, 1, + { "seqh", TILEPRO_OPC_SEQH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "seqh.sn", TILE_OPC_SEQH_SN, 0x3, 3, TREG_SN, 1, + { "seqh.sn", TILEPRO_OPC_SEQH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "seqi", TILE_OPC_SEQI, 0xf, 3, TREG_ZERO, 1, + { "seqi", TILEPRO_OPC_SEQI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, }, - { "seqi.sn", TILE_OPC_SEQI_SN, 0x3, 3, TREG_SN, 1, + { "seqi.sn", TILEPRO_OPC_SEQI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "seqib", TILE_OPC_SEQIB, 0x3, 3, TREG_ZERO, 1, + { "seqib", TILEPRO_OPC_SEQIB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "seqib.sn", TILE_OPC_SEQIB_SN, 0x3, 3, TREG_SN, 1, + { "seqib.sn", TILEPRO_OPC_SEQIB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "seqih", TILE_OPC_SEQIH, 0x3, 3, TREG_ZERO, 1, + { "seqih", TILEPRO_OPC_SEQIH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "seqih.sn", TILE_OPC_SEQIH_SN, 0x3, 3, TREG_SN, 1, + { "seqih.sn", TILEPRO_OPC_SEQIH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sh", TILE_OPC_SH, 0x12, 2, TREG_ZERO, 1, + { "sh", TILEPRO_OPC_SH, 0x12, 2, TREG_ZERO, 1, { { 0, }, { 10, 17 }, { 0, }, { 0, }, { 15, 36 } }, }, - { "shadd", TILE_OPC_SHADD, 0x2, 3, TREG_ZERO, 1, + { "shadd", TILEPRO_OPC_SHADD, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 24, 17, 37 }, { 0, }, { 0, }, { 0, } }, }, - { "shl", TILE_OPC_SHL, 0xf, 3, TREG_ZERO, 1, + { "shl", TILEPRO_OPC_SHL, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "shl.sn", TILE_OPC_SHL_SN, 0x3, 3, TREG_SN, 1, + { "shl.sn", TILEPRO_OPC_SHL_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shlb", TILE_OPC_SHLB, 0x3, 3, TREG_ZERO, 1, + { "shlb", TILEPRO_OPC_SHLB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shlb.sn", TILE_OPC_SHLB_SN, 0x3, 3, TREG_SN, 1, + { "shlb.sn", TILEPRO_OPC_SHLB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shlh", TILE_OPC_SHLH, 0x3, 3, TREG_ZERO, 1, + { "shlh", TILEPRO_OPC_SHLH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shlh.sn", TILE_OPC_SHLH_SN, 0x3, 3, TREG_SN, 1, + { "shlh.sn", TILEPRO_OPC_SHLH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shli", TILE_OPC_SHLI, 0xf, 3, TREG_ZERO, 1, + { "shli", TILEPRO_OPC_SHLI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 11, 12, 34 }, { 13, 14, 35 }, { 0, } }, }, - { "shli.sn", TILE_OPC_SHLI_SN, 0x3, 3, TREG_SN, 1, + { "shli.sn", TILEPRO_OPC_SHLI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shlib", TILE_OPC_SHLIB, 0x3, 3, TREG_ZERO, 1, + { "shlib", TILEPRO_OPC_SHLIB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shlib.sn", TILE_OPC_SHLIB_SN, 0x3, 3, TREG_SN, 1, + { "shlib.sn", TILEPRO_OPC_SHLIB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shlih", TILE_OPC_SHLIH, 0x3, 3, TREG_ZERO, 1, + { "shlih", TILEPRO_OPC_SHLIH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shlih.sn", TILE_OPC_SHLIH_SN, 0x3, 3, TREG_SN, 1, + { "shlih.sn", TILEPRO_OPC_SHLIH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shr", TILE_OPC_SHR, 0xf, 3, TREG_ZERO, 1, + { "shr", TILEPRO_OPC_SHR, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "shr.sn", TILE_OPC_SHR_SN, 0x3, 3, TREG_SN, 1, + { "shr.sn", TILEPRO_OPC_SHR_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shrb", TILE_OPC_SHRB, 0x3, 3, TREG_ZERO, 1, + { "shrb", TILEPRO_OPC_SHRB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shrb.sn", TILE_OPC_SHRB_SN, 0x3, 3, TREG_SN, 1, + { "shrb.sn", TILEPRO_OPC_SHRB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shrh", TILE_OPC_SHRH, 0x3, 3, TREG_ZERO, 1, + { "shrh", TILEPRO_OPC_SHRH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shrh.sn", TILE_OPC_SHRH_SN, 0x3, 3, TREG_SN, 1, + { "shrh.sn", TILEPRO_OPC_SHRH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "shri", TILE_OPC_SHRI, 0xf, 3, TREG_ZERO, 1, + { "shri", TILEPRO_OPC_SHRI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 11, 12, 34 }, { 13, 14, 35 }, { 0, } }, }, - { "shri.sn", TILE_OPC_SHRI_SN, 0x3, 3, TREG_SN, 1, + { "shri.sn", TILEPRO_OPC_SHRI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shrib", TILE_OPC_SHRIB, 0x3, 3, TREG_ZERO, 1, + { "shrib", TILEPRO_OPC_SHRIB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shrib.sn", TILE_OPC_SHRIB_SN, 0x3, 3, TREG_SN, 1, + { "shrib.sn", TILEPRO_OPC_SHRIB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shrih", TILE_OPC_SHRIH, 0x3, 3, TREG_ZERO, 1, + { "shrih", TILEPRO_OPC_SHRIH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "shrih.sn", TILE_OPC_SHRIH_SN, 0x3, 3, TREG_SN, 1, + { "shrih.sn", TILEPRO_OPC_SHRIH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "slt", TILE_OPC_SLT, 0xf, 3, TREG_ZERO, 1, + { "slt", TILEPRO_OPC_SLT, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "slt.sn", TILE_OPC_SLT_SN, 0x3, 3, TREG_SN, 1, + { "slt.sn", TILEPRO_OPC_SLT_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slt_u", TILE_OPC_SLT_U, 0xf, 3, TREG_ZERO, 1, + { "slt_u", TILEPRO_OPC_SLT_U, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "slt_u.sn", TILE_OPC_SLT_U_SN, 0x3, 3, TREG_SN, 1, + { "slt_u.sn", TILEPRO_OPC_SLT_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sltb", TILE_OPC_SLTB, 0x3, 3, TREG_ZERO, 1, + { "sltb", TILEPRO_OPC_SLTB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sltb.sn", TILE_OPC_SLTB_SN, 0x3, 3, TREG_SN, 1, + { "sltb.sn", TILEPRO_OPC_SLTB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sltb_u", TILE_OPC_SLTB_U, 0x3, 3, TREG_ZERO, 1, + { "sltb_u", TILEPRO_OPC_SLTB_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sltb_u.sn", TILE_OPC_SLTB_U_SN, 0x3, 3, TREG_SN, 1, + { "sltb_u.sn", TILEPRO_OPC_SLTB_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slte", TILE_OPC_SLTE, 0xf, 3, TREG_ZERO, 1, + { "slte", TILEPRO_OPC_SLTE, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "slte.sn", TILE_OPC_SLTE_SN, 0x3, 3, TREG_SN, 1, + { "slte.sn", TILEPRO_OPC_SLTE_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slte_u", TILE_OPC_SLTE_U, 0xf, 3, TREG_ZERO, 1, + { "slte_u", TILEPRO_OPC_SLTE_U, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "slte_u.sn", TILE_OPC_SLTE_U_SN, 0x3, 3, TREG_SN, 1, + { "slte_u.sn", TILEPRO_OPC_SLTE_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slteb", TILE_OPC_SLTEB, 0x3, 3, TREG_ZERO, 1, + { "slteb", TILEPRO_OPC_SLTEB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slteb.sn", TILE_OPC_SLTEB_SN, 0x3, 3, TREG_SN, 1, + { "slteb.sn", TILEPRO_OPC_SLTEB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slteb_u", TILE_OPC_SLTEB_U, 0x3, 3, TREG_ZERO, 1, + { "slteb_u", TILEPRO_OPC_SLTEB_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slteb_u.sn", TILE_OPC_SLTEB_U_SN, 0x3, 3, TREG_SN, 1, + { "slteb_u.sn", TILEPRO_OPC_SLTEB_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slteh", TILE_OPC_SLTEH, 0x3, 3, TREG_ZERO, 1, + { "slteh", TILEPRO_OPC_SLTEH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slteh.sn", TILE_OPC_SLTEH_SN, 0x3, 3, TREG_SN, 1, + { "slteh.sn", TILEPRO_OPC_SLTEH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slteh_u", TILE_OPC_SLTEH_U, 0x3, 3, TREG_ZERO, 1, + { "slteh_u", TILEPRO_OPC_SLTEH_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slteh_u.sn", TILE_OPC_SLTEH_U_SN, 0x3, 3, TREG_SN, 1, + { "slteh_u.sn", TILEPRO_OPC_SLTEH_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slth", TILE_OPC_SLTH, 0x3, 3, TREG_ZERO, 1, + { "slth", TILEPRO_OPC_SLTH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slth.sn", TILE_OPC_SLTH_SN, 0x3, 3, TREG_SN, 1, + { "slth.sn", TILEPRO_OPC_SLTH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slth_u", TILE_OPC_SLTH_U, 0x3, 3, TREG_ZERO, 1, + { "slth_u", TILEPRO_OPC_SLTH_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slth_u.sn", TILE_OPC_SLTH_U_SN, 0x3, 3, TREG_SN, 1, + { "slth_u.sn", TILEPRO_OPC_SLTH_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "slti", TILE_OPC_SLTI, 0xf, 3, TREG_ZERO, 1, + { "slti", TILEPRO_OPC_SLTI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, }, - { "slti.sn", TILE_OPC_SLTI_SN, 0x3, 3, TREG_SN, 1, + { "slti.sn", TILEPRO_OPC_SLTI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "slti_u", TILE_OPC_SLTI_U, 0xf, 3, TREG_ZERO, 1, + { "slti_u", TILEPRO_OPC_SLTI_U, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, }, - { "slti_u.sn", TILE_OPC_SLTI_U_SN, 0x3, 3, TREG_SN, 1, + { "slti_u.sn", TILEPRO_OPC_SLTI_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sltib", TILE_OPC_SLTIB, 0x3, 3, TREG_ZERO, 1, + { "sltib", TILEPRO_OPC_SLTIB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sltib.sn", TILE_OPC_SLTIB_SN, 0x3, 3, TREG_SN, 1, + { "sltib.sn", TILEPRO_OPC_SLTIB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sltib_u", TILE_OPC_SLTIB_U, 0x3, 3, TREG_ZERO, 1, + { "sltib_u", TILEPRO_OPC_SLTIB_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sltib_u.sn", TILE_OPC_SLTIB_U_SN, 0x3, 3, TREG_SN, 1, + { "sltib_u.sn", TILEPRO_OPC_SLTIB_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sltih", TILE_OPC_SLTIH, 0x3, 3, TREG_ZERO, 1, + { "sltih", TILEPRO_OPC_SLTIH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sltih.sn", TILE_OPC_SLTIH_SN, 0x3, 3, TREG_SN, 1, + { "sltih.sn", TILEPRO_OPC_SLTIH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sltih_u", TILE_OPC_SLTIH_U, 0x3, 3, TREG_ZERO, 1, + { "sltih_u", TILEPRO_OPC_SLTIH_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sltih_u.sn", TILE_OPC_SLTIH_U_SN, 0x3, 3, TREG_SN, 1, + { "sltih_u.sn", TILEPRO_OPC_SLTIH_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "sne", TILE_OPC_SNE, 0xf, 3, TREG_ZERO, 1, + { "sne", TILEPRO_OPC_SNE, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "sne.sn", TILE_OPC_SNE_SN, 0x3, 3, TREG_SN, 1, + { "sne.sn", TILEPRO_OPC_SNE_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sneb", TILE_OPC_SNEB, 0x3, 3, TREG_ZERO, 1, + { "sneb", TILEPRO_OPC_SNEB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sneb.sn", TILE_OPC_SNEB_SN, 0x3, 3, TREG_SN, 1, + { "sneb.sn", TILEPRO_OPC_SNEB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sneh", TILE_OPC_SNEH, 0x3, 3, TREG_ZERO, 1, + { "sneh", TILEPRO_OPC_SNEH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sneh.sn", TILE_OPC_SNEH_SN, 0x3, 3, TREG_SN, 1, + { "sneh.sn", TILEPRO_OPC_SNEH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sra", TILE_OPC_SRA, 0xf, 3, TREG_ZERO, 1, + { "sra", TILEPRO_OPC_SRA, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "sra.sn", TILE_OPC_SRA_SN, 0x3, 3, TREG_SN, 1, + { "sra.sn", TILEPRO_OPC_SRA_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "srab", TILE_OPC_SRAB, 0x3, 3, TREG_ZERO, 1, + { "srab", TILEPRO_OPC_SRAB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "srab.sn", TILE_OPC_SRAB_SN, 0x3, 3, TREG_SN, 1, + { "srab.sn", TILEPRO_OPC_SRAB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "srah", TILE_OPC_SRAH, 0x3, 3, TREG_ZERO, 1, + { "srah", TILEPRO_OPC_SRAH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "srah.sn", TILE_OPC_SRAH_SN, 0x3, 3, TREG_SN, 1, + { "srah.sn", TILEPRO_OPC_SRAH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "srai", TILE_OPC_SRAI, 0xf, 3, TREG_ZERO, 1, + { "srai", TILEPRO_OPC_SRAI, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 11, 12, 34 }, { 13, 14, 35 }, { 0, } }, }, - { "srai.sn", TILE_OPC_SRAI_SN, 0x3, 3, TREG_SN, 1, + { "srai.sn", TILEPRO_OPC_SRAI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "sraib", TILE_OPC_SRAIB, 0x3, 3, TREG_ZERO, 1, + { "sraib", TILEPRO_OPC_SRAIB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "sraib.sn", TILE_OPC_SRAIB_SN, 0x3, 3, TREG_SN, 1, + { "sraib.sn", TILEPRO_OPC_SRAIB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "sraih", TILE_OPC_SRAIH, 0x3, 3, TREG_ZERO, 1, + { "sraih", TILEPRO_OPC_SRAIH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "sraih.sn", TILE_OPC_SRAIH_SN, 0x3, 3, TREG_SN, 1, + { "sraih.sn", TILEPRO_OPC_SRAIH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, }, - { "sub", TILE_OPC_SUB, 0xf, 3, TREG_ZERO, 1, + { "sub", TILEPRO_OPC_SUB, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "sub.sn", TILE_OPC_SUB_SN, 0x3, 3, TREG_SN, 1, + { "sub.sn", TILEPRO_OPC_SUB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subb", TILE_OPC_SUBB, 0x3, 3, TREG_ZERO, 1, + { "subb", TILEPRO_OPC_SUBB, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subb.sn", TILE_OPC_SUBB_SN, 0x3, 3, TREG_SN, 1, + { "subb.sn", TILEPRO_OPC_SUBB_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subbs_u", TILE_OPC_SUBBS_U, 0x3, 3, TREG_ZERO, 1, + { "subbs_u", TILEPRO_OPC_SUBBS_U, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subbs_u.sn", TILE_OPC_SUBBS_U_SN, 0x3, 3, TREG_SN, 1, + { "subbs_u.sn", TILEPRO_OPC_SUBBS_U_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subh", TILE_OPC_SUBH, 0x3, 3, TREG_ZERO, 1, + { "subh", TILEPRO_OPC_SUBH, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subh.sn", TILE_OPC_SUBH_SN, 0x3, 3, TREG_SN, 1, + { "subh.sn", TILEPRO_OPC_SUBH_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subhs", TILE_OPC_SUBHS, 0x3, 3, TREG_ZERO, 1, + { "subhs", TILEPRO_OPC_SUBHS, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subhs.sn", TILE_OPC_SUBHS_SN, 0x3, 3, TREG_SN, 1, + { "subhs.sn", TILEPRO_OPC_SUBHS_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subs", TILE_OPC_SUBS, 0x3, 3, TREG_ZERO, 1, + { "subs", TILEPRO_OPC_SUBS, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "subs.sn", TILE_OPC_SUBS_SN, 0x3, 3, TREG_SN, 1, + { "subs.sn", TILEPRO_OPC_SUBS_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "sw", TILE_OPC_SW, 0x12, 2, TREG_ZERO, 1, + { "sw", TILEPRO_OPC_SW, 0x12, 2, TREG_ZERO, 1, { { 0, }, { 10, 17 }, { 0, }, { 0, }, { 15, 36 } }, }, - { "swadd", TILE_OPC_SWADD, 0x2, 3, TREG_ZERO, 1, + { "swadd", TILEPRO_OPC_SWADD, 0x2, 3, TREG_ZERO, 1, { { 0, }, { 24, 17, 37 }, { 0, }, { 0, }, { 0, } }, }, - { "swint0", TILE_OPC_SWINT0, 0x2, 0, TREG_ZERO, 0, + { "swint0", TILEPRO_OPC_SWINT0, 0x2, 0, TREG_ZERO, 0, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "swint1", TILE_OPC_SWINT1, 0x2, 0, TREG_ZERO, 0, + { "swint1", TILEPRO_OPC_SWINT1, 0x2, 0, TREG_ZERO, 0, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "swint2", TILE_OPC_SWINT2, 0x2, 0, TREG_ZERO, 0, + { "swint2", TILEPRO_OPC_SWINT2, 0x2, 0, TREG_ZERO, 0, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "swint3", TILE_OPC_SWINT3, 0x2, 0, TREG_ZERO, 0, + { "swint3", TILEPRO_OPC_SWINT3, 0x2, 0, TREG_ZERO, 0, { { 0, }, { }, { 0, }, { 0, }, { 0, } }, }, - { "tblidxb0", TILE_OPC_TBLIDXB0, 0x5, 2, TREG_ZERO, 1, + { "tblidxb0", TILEPRO_OPC_TBLIDXB0, 0x5, 2, TREG_ZERO, 1, { { 21, 8 }, { 0, }, { 31, 12 }, { 0, }, { 0, } }, }, - { "tblidxb0.sn", TILE_OPC_TBLIDXB0_SN, 0x1, 2, TREG_SN, 1, + { "tblidxb0.sn", TILEPRO_OPC_TBLIDXB0_SN, 0x1, 2, TREG_SN, 1, { { 21, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "tblidxb1", TILE_OPC_TBLIDXB1, 0x5, 2, TREG_ZERO, 1, + { "tblidxb1", TILEPRO_OPC_TBLIDXB1, 0x5, 2, TREG_ZERO, 1, { { 21, 8 }, { 0, }, { 31, 12 }, { 0, }, { 0, } }, }, - { "tblidxb1.sn", TILE_OPC_TBLIDXB1_SN, 0x1, 2, TREG_SN, 1, + { "tblidxb1.sn", TILEPRO_OPC_TBLIDXB1_SN, 0x1, 2, TREG_SN, 1, { { 21, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "tblidxb2", TILE_OPC_TBLIDXB2, 0x5, 2, TREG_ZERO, 1, + { "tblidxb2", TILEPRO_OPC_TBLIDXB2, 0x5, 2, TREG_ZERO, 1, { { 21, 8 }, { 0, }, { 31, 12 }, { 0, }, { 0, } }, }, - { "tblidxb2.sn", TILE_OPC_TBLIDXB2_SN, 0x1, 2, TREG_SN, 1, + { "tblidxb2.sn", TILEPRO_OPC_TBLIDXB2_SN, 0x1, 2, TREG_SN, 1, { { 21, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "tblidxb3", TILE_OPC_TBLIDXB3, 0x5, 2, TREG_ZERO, 1, + { "tblidxb3", TILEPRO_OPC_TBLIDXB3, 0x5, 2, TREG_ZERO, 1, { { 21, 8 }, { 0, }, { 31, 12 }, { 0, }, { 0, } }, }, - { "tblidxb3.sn", TILE_OPC_TBLIDXB3_SN, 0x1, 2, TREG_SN, 1, + { "tblidxb3.sn", TILEPRO_OPC_TBLIDXB3_SN, 0x1, 2, TREG_SN, 1, { { 21, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, }, - { "tns", TILE_OPC_TNS, 0x2, 2, TREG_ZERO, 1, + { "tns", TILEPRO_OPC_TNS, 0x2, 2, TREG_ZERO, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "tns.sn", TILE_OPC_TNS_SN, 0x2, 2, TREG_SN, 1, + { "tns.sn", TILEPRO_OPC_TNS_SN, 0x2, 2, TREG_SN, 1, { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, }, - { "wh64", TILE_OPC_WH64, 0x2, 1, TREG_ZERO, 1, + { "wh64", TILEPRO_OPC_WH64, 0x2, 1, TREG_ZERO, 1, { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, }, - { "xor", TILE_OPC_XOR, 0xf, 3, TREG_ZERO, 1, + { "xor", TILEPRO_OPC_XOR, 0xf, 3, TREG_ZERO, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, }, - { "xor.sn", TILE_OPC_XOR_SN, 0x3, 3, TREG_SN, 1, + { "xor.sn", TILEPRO_OPC_XOR_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, }, - { "xori", TILE_OPC_XORI, 0x3, 3, TREG_ZERO, 1, + { "xori", TILEPRO_OPC_XORI, 0x3, 3, TREG_ZERO, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { "xori.sn", TILE_OPC_XORI_SN, 0x3, 3, TREG_SN, 1, + { "xori.sn", TILEPRO_OPC_XORI_SN, 0x3, 3, TREG_SN, 1, { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, }, - { NULL, TILE_OPC_NONE, 0, 0, TREG_ZERO, 0, { { 0, } }, + { NULL, TILEPRO_OPC_NONE, 0, 0, TREG_ZERO, 0, { { 0, } }, } }; #define BITFIELD(start, size) ((start) | (((1 << (size)) - 1) << 6)) -#define CHILD(array_index) (TILE_OPC_NONE + (array_index)) +#define CHILD(array_index) (TILEPRO_OPC_NONE + (array_index)) static const unsigned short decode_X0_fsm[1153] = { BITFIELD(22, 9) /* index 0 */, CHILD(513), CHILD(530), CHILD(547), CHILD(564), CHILD(596), CHILD(613), - CHILD(630), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, CHILD(663), CHILD(680), CHILD(697), CHILD(714), CHILD(746), - CHILD(763), CHILD(780), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, CHILD(813), CHILD(813), CHILD(813), + CHILD(630), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(663), CHILD(680), CHILD(697), + CHILD(714), CHILD(746), CHILD(763), CHILD(780), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), @@ -1227,7 +1247,8 @@ static const unsigned short decode_X0_fsm[1153] = CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), + CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(828), CHILD(828), + CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), @@ -1237,7 +1258,7 @@ static const unsigned short decode_X0_fsm[1153] = CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(843), + CHILD(828), CHILD(828), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), @@ -1248,333 +1269,371 @@ static const unsigned short decode_X0_fsm[1153] = CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(873), CHILD(878), CHILD(883), - CHILD(903), CHILD(908), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(913), - CHILD(918), CHILD(923), CHILD(943), CHILD(948), TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, CHILD(953), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(988), TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, CHILD(993), - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, CHILD(1076), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + CHILD(873), CHILD(878), CHILD(883), CHILD(903), CHILD(908), + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(913), + CHILD(918), CHILD(923), CHILD(943), CHILD(948), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(953), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(988), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, CHILD(993), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(1076), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(18, 4) /* index 513 */, - TILE_OPC_NONE, TILE_OPC_ADDB, TILE_OPC_ADDH, TILE_OPC_ADD, - TILE_OPC_ADIFFB_U, TILE_OPC_ADIFFH, TILE_OPC_AND, TILE_OPC_AVGB_U, - TILE_OPC_AVGH, TILE_OPC_CRC32_32, TILE_OPC_CRC32_8, TILE_OPC_INTHB, - TILE_OPC_INTHH, TILE_OPC_INTLB, TILE_OPC_INTLH, TILE_OPC_MAXB_U, + TILEPRO_OPC_NONE, TILEPRO_OPC_ADDB, TILEPRO_OPC_ADDH, TILEPRO_OPC_ADD, + TILEPRO_OPC_ADIFFB_U, TILEPRO_OPC_ADIFFH, TILEPRO_OPC_AND, + TILEPRO_OPC_AVGB_U, TILEPRO_OPC_AVGH, TILEPRO_OPC_CRC32_32, + TILEPRO_OPC_CRC32_8, TILEPRO_OPC_INTHB, TILEPRO_OPC_INTHH, + TILEPRO_OPC_INTLB, TILEPRO_OPC_INTLH, TILEPRO_OPC_MAXB_U, BITFIELD(18, 4) /* index 530 */, - TILE_OPC_MAXH, TILE_OPC_MINB_U, TILE_OPC_MINH, TILE_OPC_MNZB, TILE_OPC_MNZH, - TILE_OPC_MNZ, TILE_OPC_MULHHA_SS, TILE_OPC_MULHHA_SU, TILE_OPC_MULHHA_UU, - TILE_OPC_MULHHSA_UU, TILE_OPC_MULHH_SS, TILE_OPC_MULHH_SU, - TILE_OPC_MULHH_UU, TILE_OPC_MULHLA_SS, TILE_OPC_MULHLA_SU, - TILE_OPC_MULHLA_US, + TILEPRO_OPC_MAXH, TILEPRO_OPC_MINB_U, TILEPRO_OPC_MINH, TILEPRO_OPC_MNZB, + TILEPRO_OPC_MNZH, TILEPRO_OPC_MNZ, TILEPRO_OPC_MULHHA_SS, + TILEPRO_OPC_MULHHA_SU, TILEPRO_OPC_MULHHA_UU, TILEPRO_OPC_MULHHSA_UU, + TILEPRO_OPC_MULHH_SS, TILEPRO_OPC_MULHH_SU, TILEPRO_OPC_MULHH_UU, + TILEPRO_OPC_MULHLA_SS, TILEPRO_OPC_MULHLA_SU, TILEPRO_OPC_MULHLA_US, BITFIELD(18, 4) /* index 547 */, - TILE_OPC_MULHLA_UU, TILE_OPC_MULHLSA_UU, TILE_OPC_MULHL_SS, - TILE_OPC_MULHL_SU, TILE_OPC_MULHL_US, TILE_OPC_MULHL_UU, TILE_OPC_MULLLA_SS, - TILE_OPC_MULLLA_SU, TILE_OPC_MULLLA_UU, TILE_OPC_MULLLSA_UU, - TILE_OPC_MULLL_SS, TILE_OPC_MULLL_SU, TILE_OPC_MULLL_UU, TILE_OPC_MVNZ, - TILE_OPC_MVZ, TILE_OPC_MZB, + TILEPRO_OPC_MULHLA_UU, TILEPRO_OPC_MULHLSA_UU, TILEPRO_OPC_MULHL_SS, + TILEPRO_OPC_MULHL_SU, TILEPRO_OPC_MULHL_US, TILEPRO_OPC_MULHL_UU, + TILEPRO_OPC_MULLLA_SS, TILEPRO_OPC_MULLLA_SU, TILEPRO_OPC_MULLLA_UU, + TILEPRO_OPC_MULLLSA_UU, TILEPRO_OPC_MULLL_SS, TILEPRO_OPC_MULLL_SU, + TILEPRO_OPC_MULLL_UU, TILEPRO_OPC_MVNZ, TILEPRO_OPC_MVZ, TILEPRO_OPC_MZB, BITFIELD(18, 4) /* index 564 */, - TILE_OPC_MZH, TILE_OPC_MZ, TILE_OPC_NOR, CHILD(581), TILE_OPC_PACKHB, - TILE_OPC_PACKLB, TILE_OPC_RL, TILE_OPC_S1A, TILE_OPC_S2A, TILE_OPC_S3A, - TILE_OPC_SADAB_U, TILE_OPC_SADAH, TILE_OPC_SADAH_U, TILE_OPC_SADB_U, - TILE_OPC_SADH, TILE_OPC_SADH_U, + TILEPRO_OPC_MZH, TILEPRO_OPC_MZ, TILEPRO_OPC_NOR, CHILD(581), + TILEPRO_OPC_PACKHB, TILEPRO_OPC_PACKLB, TILEPRO_OPC_RL, TILEPRO_OPC_S1A, + TILEPRO_OPC_S2A, TILEPRO_OPC_S3A, TILEPRO_OPC_SADAB_U, TILEPRO_OPC_SADAH, + TILEPRO_OPC_SADAH_U, TILEPRO_OPC_SADB_U, TILEPRO_OPC_SADH, + TILEPRO_OPC_SADH_U, BITFIELD(12, 2) /* index 581 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(586), + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(586), BITFIELD(14, 2) /* index 586 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(591), + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(591), BITFIELD(16, 2) /* index 591 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_MOVE, + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_MOVE, BITFIELD(18, 4) /* index 596 */, - TILE_OPC_SEQB, TILE_OPC_SEQH, TILE_OPC_SEQ, TILE_OPC_SHLB, TILE_OPC_SHLH, - TILE_OPC_SHL, TILE_OPC_SHRB, TILE_OPC_SHRH, TILE_OPC_SHR, TILE_OPC_SLTB, - TILE_OPC_SLTB_U, TILE_OPC_SLTEB, TILE_OPC_SLTEB_U, TILE_OPC_SLTEH, - TILE_OPC_SLTEH_U, TILE_OPC_SLTE, + TILEPRO_OPC_SEQB, TILEPRO_OPC_SEQH, TILEPRO_OPC_SEQ, TILEPRO_OPC_SHLB, + TILEPRO_OPC_SHLH, TILEPRO_OPC_SHL, TILEPRO_OPC_SHRB, TILEPRO_OPC_SHRH, + TILEPRO_OPC_SHR, TILEPRO_OPC_SLTB, TILEPRO_OPC_SLTB_U, TILEPRO_OPC_SLTEB, + TILEPRO_OPC_SLTEB_U, TILEPRO_OPC_SLTEH, TILEPRO_OPC_SLTEH_U, + TILEPRO_OPC_SLTE, BITFIELD(18, 4) /* index 613 */, - TILE_OPC_SLTE_U, TILE_OPC_SLTH, TILE_OPC_SLTH_U, TILE_OPC_SLT, - TILE_OPC_SLT_U, TILE_OPC_SNEB, TILE_OPC_SNEH, TILE_OPC_SNE, TILE_OPC_SRAB, - TILE_OPC_SRAH, TILE_OPC_SRA, TILE_OPC_SUBB, TILE_OPC_SUBH, TILE_OPC_SUB, - TILE_OPC_XOR, TILE_OPC_DWORD_ALIGN, + TILEPRO_OPC_SLTE_U, TILEPRO_OPC_SLTH, TILEPRO_OPC_SLTH_U, TILEPRO_OPC_SLT, + TILEPRO_OPC_SLT_U, TILEPRO_OPC_SNEB, TILEPRO_OPC_SNEH, TILEPRO_OPC_SNE, + TILEPRO_OPC_SRAB, TILEPRO_OPC_SRAH, TILEPRO_OPC_SRA, TILEPRO_OPC_SUBB, + TILEPRO_OPC_SUBH, TILEPRO_OPC_SUB, TILEPRO_OPC_XOR, TILEPRO_OPC_DWORD_ALIGN, BITFIELD(18, 3) /* index 630 */, CHILD(639), CHILD(642), CHILD(645), CHILD(648), CHILD(651), CHILD(654), CHILD(657), CHILD(660), BITFIELD(21, 1) /* index 639 */, - TILE_OPC_ADDS, TILE_OPC_NONE, + TILEPRO_OPC_ADDS, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 642 */, - TILE_OPC_SUBS, TILE_OPC_NONE, + TILEPRO_OPC_SUBS, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 645 */, - TILE_OPC_ADDBS_U, TILE_OPC_NONE, + TILEPRO_OPC_ADDBS_U, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 648 */, - TILE_OPC_ADDHS, TILE_OPC_NONE, + TILEPRO_OPC_ADDHS, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 651 */, - TILE_OPC_SUBBS_U, TILE_OPC_NONE, + TILEPRO_OPC_SUBBS_U, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 654 */, - TILE_OPC_SUBHS, TILE_OPC_NONE, + TILEPRO_OPC_SUBHS, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 657 */, - TILE_OPC_PACKHS, TILE_OPC_NONE, + TILEPRO_OPC_PACKHS, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 660 */, - TILE_OPC_PACKBS_U, TILE_OPC_NONE, + TILEPRO_OPC_PACKBS_U, TILEPRO_OPC_NONE, BITFIELD(18, 4) /* index 663 */, - TILE_OPC_NONE, TILE_OPC_ADDB_SN, TILE_OPC_ADDH_SN, TILE_OPC_ADD_SN, - TILE_OPC_ADIFFB_U_SN, TILE_OPC_ADIFFH_SN, TILE_OPC_AND_SN, - TILE_OPC_AVGB_U_SN, TILE_OPC_AVGH_SN, TILE_OPC_CRC32_32_SN, - TILE_OPC_CRC32_8_SN, TILE_OPC_INTHB_SN, TILE_OPC_INTHH_SN, - TILE_OPC_INTLB_SN, TILE_OPC_INTLH_SN, TILE_OPC_MAXB_U_SN, + TILEPRO_OPC_NONE, TILEPRO_OPC_ADDB_SN, TILEPRO_OPC_ADDH_SN, + TILEPRO_OPC_ADD_SN, TILEPRO_OPC_ADIFFB_U_SN, TILEPRO_OPC_ADIFFH_SN, + TILEPRO_OPC_AND_SN, TILEPRO_OPC_AVGB_U_SN, TILEPRO_OPC_AVGH_SN, + TILEPRO_OPC_CRC32_32_SN, TILEPRO_OPC_CRC32_8_SN, TILEPRO_OPC_INTHB_SN, + TILEPRO_OPC_INTHH_SN, TILEPRO_OPC_INTLB_SN, TILEPRO_OPC_INTLH_SN, + TILEPRO_OPC_MAXB_U_SN, BITFIELD(18, 4) /* index 680 */, - TILE_OPC_MAXH_SN, TILE_OPC_MINB_U_SN, TILE_OPC_MINH_SN, TILE_OPC_MNZB_SN, - TILE_OPC_MNZH_SN, TILE_OPC_MNZ_SN, TILE_OPC_MULHHA_SS_SN, - TILE_OPC_MULHHA_SU_SN, TILE_OPC_MULHHA_UU_SN, TILE_OPC_MULHHSA_UU_SN, - TILE_OPC_MULHH_SS_SN, TILE_OPC_MULHH_SU_SN, TILE_OPC_MULHH_UU_SN, - TILE_OPC_MULHLA_SS_SN, TILE_OPC_MULHLA_SU_SN, TILE_OPC_MULHLA_US_SN, + TILEPRO_OPC_MAXH_SN, TILEPRO_OPC_MINB_U_SN, TILEPRO_OPC_MINH_SN, + TILEPRO_OPC_MNZB_SN, TILEPRO_OPC_MNZH_SN, TILEPRO_OPC_MNZ_SN, + TILEPRO_OPC_MULHHA_SS_SN, TILEPRO_OPC_MULHHA_SU_SN, + TILEPRO_OPC_MULHHA_UU_SN, TILEPRO_OPC_MULHHSA_UU_SN, + TILEPRO_OPC_MULHH_SS_SN, TILEPRO_OPC_MULHH_SU_SN, TILEPRO_OPC_MULHH_UU_SN, + TILEPRO_OPC_MULHLA_SS_SN, TILEPRO_OPC_MULHLA_SU_SN, + TILEPRO_OPC_MULHLA_US_SN, BITFIELD(18, 4) /* index 697 */, - TILE_OPC_MULHLA_UU_SN, TILE_OPC_MULHLSA_UU_SN, TILE_OPC_MULHL_SS_SN, - TILE_OPC_MULHL_SU_SN, TILE_OPC_MULHL_US_SN, TILE_OPC_MULHL_UU_SN, - TILE_OPC_MULLLA_SS_SN, TILE_OPC_MULLLA_SU_SN, TILE_OPC_MULLLA_UU_SN, - TILE_OPC_MULLLSA_UU_SN, TILE_OPC_MULLL_SS_SN, TILE_OPC_MULLL_SU_SN, - TILE_OPC_MULLL_UU_SN, TILE_OPC_MVNZ_SN, TILE_OPC_MVZ_SN, TILE_OPC_MZB_SN, + TILEPRO_OPC_MULHLA_UU_SN, TILEPRO_OPC_MULHLSA_UU_SN, + TILEPRO_OPC_MULHL_SS_SN, TILEPRO_OPC_MULHL_SU_SN, TILEPRO_OPC_MULHL_US_SN, + TILEPRO_OPC_MULHL_UU_SN, TILEPRO_OPC_MULLLA_SS_SN, TILEPRO_OPC_MULLLA_SU_SN, + TILEPRO_OPC_MULLLA_UU_SN, TILEPRO_OPC_MULLLSA_UU_SN, + TILEPRO_OPC_MULLL_SS_SN, TILEPRO_OPC_MULLL_SU_SN, TILEPRO_OPC_MULLL_UU_SN, + TILEPRO_OPC_MVNZ_SN, TILEPRO_OPC_MVZ_SN, TILEPRO_OPC_MZB_SN, BITFIELD(18, 4) /* index 714 */, - TILE_OPC_MZH_SN, TILE_OPC_MZ_SN, TILE_OPC_NOR_SN, CHILD(731), - TILE_OPC_PACKHB_SN, TILE_OPC_PACKLB_SN, TILE_OPC_RL_SN, TILE_OPC_S1A_SN, - TILE_OPC_S2A_SN, TILE_OPC_S3A_SN, TILE_OPC_SADAB_U_SN, TILE_OPC_SADAH_SN, - TILE_OPC_SADAH_U_SN, TILE_OPC_SADB_U_SN, TILE_OPC_SADH_SN, - TILE_OPC_SADH_U_SN, + TILEPRO_OPC_MZH_SN, TILEPRO_OPC_MZ_SN, TILEPRO_OPC_NOR_SN, CHILD(731), + TILEPRO_OPC_PACKHB_SN, TILEPRO_OPC_PACKLB_SN, TILEPRO_OPC_RL_SN, + TILEPRO_OPC_S1A_SN, TILEPRO_OPC_S2A_SN, TILEPRO_OPC_S3A_SN, + TILEPRO_OPC_SADAB_U_SN, TILEPRO_OPC_SADAH_SN, TILEPRO_OPC_SADAH_U_SN, + TILEPRO_OPC_SADB_U_SN, TILEPRO_OPC_SADH_SN, TILEPRO_OPC_SADH_U_SN, BITFIELD(12, 2) /* index 731 */, - TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, CHILD(736), + TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, CHILD(736), BITFIELD(14, 2) /* index 736 */, - TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, CHILD(741), + TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, CHILD(741), BITFIELD(16, 2) /* index 741 */, - TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_MOVE_SN, + TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, + TILEPRO_OPC_MOVE_SN, BITFIELD(18, 4) /* index 746 */, - TILE_OPC_SEQB_SN, TILE_OPC_SEQH_SN, TILE_OPC_SEQ_SN, TILE_OPC_SHLB_SN, - TILE_OPC_SHLH_SN, TILE_OPC_SHL_SN, TILE_OPC_SHRB_SN, TILE_OPC_SHRH_SN, - TILE_OPC_SHR_SN, TILE_OPC_SLTB_SN, TILE_OPC_SLTB_U_SN, TILE_OPC_SLTEB_SN, - TILE_OPC_SLTEB_U_SN, TILE_OPC_SLTEH_SN, TILE_OPC_SLTEH_U_SN, - TILE_OPC_SLTE_SN, + TILEPRO_OPC_SEQB_SN, TILEPRO_OPC_SEQH_SN, TILEPRO_OPC_SEQ_SN, + TILEPRO_OPC_SHLB_SN, TILEPRO_OPC_SHLH_SN, TILEPRO_OPC_SHL_SN, + TILEPRO_OPC_SHRB_SN, TILEPRO_OPC_SHRH_SN, TILEPRO_OPC_SHR_SN, + TILEPRO_OPC_SLTB_SN, TILEPRO_OPC_SLTB_U_SN, TILEPRO_OPC_SLTEB_SN, + TILEPRO_OPC_SLTEB_U_SN, TILEPRO_OPC_SLTEH_SN, TILEPRO_OPC_SLTEH_U_SN, + TILEPRO_OPC_SLTE_SN, BITFIELD(18, 4) /* index 763 */, - TILE_OPC_SLTE_U_SN, TILE_OPC_SLTH_SN, TILE_OPC_SLTH_U_SN, TILE_OPC_SLT_SN, - TILE_OPC_SLT_U_SN, TILE_OPC_SNEB_SN, TILE_OPC_SNEH_SN, TILE_OPC_SNE_SN, - TILE_OPC_SRAB_SN, TILE_OPC_SRAH_SN, TILE_OPC_SRA_SN, TILE_OPC_SUBB_SN, - TILE_OPC_SUBH_SN, TILE_OPC_SUB_SN, TILE_OPC_XOR_SN, TILE_OPC_DWORD_ALIGN_SN, + TILEPRO_OPC_SLTE_U_SN, TILEPRO_OPC_SLTH_SN, TILEPRO_OPC_SLTH_U_SN, + TILEPRO_OPC_SLT_SN, TILEPRO_OPC_SLT_U_SN, TILEPRO_OPC_SNEB_SN, + TILEPRO_OPC_SNEH_SN, TILEPRO_OPC_SNE_SN, TILEPRO_OPC_SRAB_SN, + TILEPRO_OPC_SRAH_SN, TILEPRO_OPC_SRA_SN, TILEPRO_OPC_SUBB_SN, + TILEPRO_OPC_SUBH_SN, TILEPRO_OPC_SUB_SN, TILEPRO_OPC_XOR_SN, + TILEPRO_OPC_DWORD_ALIGN_SN, BITFIELD(18, 3) /* index 780 */, CHILD(789), CHILD(792), CHILD(795), CHILD(798), CHILD(801), CHILD(804), CHILD(807), CHILD(810), BITFIELD(21, 1) /* index 789 */, - TILE_OPC_ADDS_SN, TILE_OPC_NONE, + TILEPRO_OPC_ADDS_SN, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 792 */, - TILE_OPC_SUBS_SN, TILE_OPC_NONE, + TILEPRO_OPC_SUBS_SN, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 795 */, - TILE_OPC_ADDBS_U_SN, TILE_OPC_NONE, + TILEPRO_OPC_ADDBS_U_SN, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 798 */, - TILE_OPC_ADDHS_SN, TILE_OPC_NONE, + TILEPRO_OPC_ADDHS_SN, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 801 */, - TILE_OPC_SUBBS_U_SN, TILE_OPC_NONE, + TILEPRO_OPC_SUBBS_U_SN, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 804 */, - TILE_OPC_SUBHS_SN, TILE_OPC_NONE, + TILEPRO_OPC_SUBHS_SN, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 807 */, - TILE_OPC_PACKHS_SN, TILE_OPC_NONE, + TILEPRO_OPC_PACKHS_SN, TILEPRO_OPC_NONE, BITFIELD(21, 1) /* index 810 */, - TILE_OPC_PACKBS_U_SN, TILE_OPC_NONE, + TILEPRO_OPC_PACKBS_U_SN, TILEPRO_OPC_NONE, BITFIELD(6, 2) /* index 813 */, - TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, CHILD(818), + TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, + CHILD(818), BITFIELD(8, 2) /* index 818 */, - TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, CHILD(823), + TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, + CHILD(823), BITFIELD(10, 2) /* index 823 */, - TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_MOVELI_SN, + TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, + TILEPRO_OPC_MOVELI_SN, BITFIELD(6, 2) /* index 828 */, - TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, CHILD(833), + TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, CHILD(833), BITFIELD(8, 2) /* index 833 */, - TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, CHILD(838), + TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, CHILD(838), BITFIELD(10, 2) /* index 838 */, - TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_MOVELI, + TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_MOVELI, BITFIELD(0, 2) /* index 843 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(848), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(848), BITFIELD(2, 2) /* index 848 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(853), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(853), BITFIELD(4, 2) /* index 853 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(858), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(858), BITFIELD(6, 2) /* index 858 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(863), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(863), BITFIELD(8, 2) /* index 863 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(868), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(868), BITFIELD(10, 2) /* index 868 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_INFOL, + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_INFOL, BITFIELD(20, 2) /* index 873 */, - TILE_OPC_NONE, TILE_OPC_ADDIB, TILE_OPC_ADDIH, TILE_OPC_ADDI, + TILEPRO_OPC_NONE, TILEPRO_OPC_ADDIB, TILEPRO_OPC_ADDIH, TILEPRO_OPC_ADDI, BITFIELD(20, 2) /* index 878 */, - TILE_OPC_MAXIB_U, TILE_OPC_MAXIH, TILE_OPC_MINIB_U, TILE_OPC_MINIH, + TILEPRO_OPC_MAXIB_U, TILEPRO_OPC_MAXIH, TILEPRO_OPC_MINIB_U, + TILEPRO_OPC_MINIH, BITFIELD(20, 2) /* index 883 */, - CHILD(888), TILE_OPC_SEQIB, TILE_OPC_SEQIH, TILE_OPC_SEQI, + CHILD(888), TILEPRO_OPC_SEQIB, TILEPRO_OPC_SEQIH, TILEPRO_OPC_SEQI, BITFIELD(6, 2) /* index 888 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(893), + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(893), BITFIELD(8, 2) /* index 893 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(898), + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(898), BITFIELD(10, 2) /* index 898 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_MOVEI, + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_MOVEI, BITFIELD(20, 2) /* index 903 */, - TILE_OPC_SLTIB, TILE_OPC_SLTIB_U, TILE_OPC_SLTIH, TILE_OPC_SLTIH_U, + TILEPRO_OPC_SLTIB, TILEPRO_OPC_SLTIB_U, TILEPRO_OPC_SLTIH, + TILEPRO_OPC_SLTIH_U, BITFIELD(20, 2) /* index 908 */, - TILE_OPC_SLTI, TILE_OPC_SLTI_U, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_SLTI, TILEPRO_OPC_SLTI_U, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(20, 2) /* index 913 */, - TILE_OPC_NONE, TILE_OPC_ADDIB_SN, TILE_OPC_ADDIH_SN, TILE_OPC_ADDI_SN, + TILEPRO_OPC_NONE, TILEPRO_OPC_ADDIB_SN, TILEPRO_OPC_ADDIH_SN, + TILEPRO_OPC_ADDI_SN, BITFIELD(20, 2) /* index 918 */, - TILE_OPC_MAXIB_U_SN, TILE_OPC_MAXIH_SN, TILE_OPC_MINIB_U_SN, - TILE_OPC_MINIH_SN, + TILEPRO_OPC_MAXIB_U_SN, TILEPRO_OPC_MAXIH_SN, TILEPRO_OPC_MINIB_U_SN, + TILEPRO_OPC_MINIH_SN, BITFIELD(20, 2) /* index 923 */, - CHILD(928), TILE_OPC_SEQIB_SN, TILE_OPC_SEQIH_SN, TILE_OPC_SEQI_SN, + CHILD(928), TILEPRO_OPC_SEQIB_SN, TILEPRO_OPC_SEQIH_SN, TILEPRO_OPC_SEQI_SN, BITFIELD(6, 2) /* index 928 */, - TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, CHILD(933), + TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, CHILD(933), BITFIELD(8, 2) /* index 933 */, - TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, CHILD(938), + TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, CHILD(938), BITFIELD(10, 2) /* index 938 */, - TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_MOVEI_SN, + TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, + TILEPRO_OPC_MOVEI_SN, BITFIELD(20, 2) /* index 943 */, - TILE_OPC_SLTIB_SN, TILE_OPC_SLTIB_U_SN, TILE_OPC_SLTIH_SN, - TILE_OPC_SLTIH_U_SN, + TILEPRO_OPC_SLTIB_SN, TILEPRO_OPC_SLTIB_U_SN, TILEPRO_OPC_SLTIH_SN, + TILEPRO_OPC_SLTIH_U_SN, BITFIELD(20, 2) /* index 948 */, - TILE_OPC_SLTI_SN, TILE_OPC_SLTI_U_SN, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_SLTI_SN, TILEPRO_OPC_SLTI_U_SN, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, BITFIELD(20, 2) /* index 953 */, - TILE_OPC_NONE, CHILD(958), TILE_OPC_XORI, TILE_OPC_NONE, + TILEPRO_OPC_NONE, CHILD(958), TILEPRO_OPC_XORI, TILEPRO_OPC_NONE, BITFIELD(0, 2) /* index 958 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(963), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(963), BITFIELD(2, 2) /* index 963 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(968), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(968), BITFIELD(4, 2) /* index 968 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(973), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(973), BITFIELD(6, 2) /* index 973 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(978), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(978), BITFIELD(8, 2) /* index 978 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(983), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(983), BITFIELD(10, 2) /* index 983 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_INFO, + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_INFO, BITFIELD(20, 2) /* index 988 */, - TILE_OPC_NONE, TILE_OPC_ANDI_SN, TILE_OPC_XORI_SN, TILE_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_ANDI_SN, TILEPRO_OPC_XORI_SN, + TILEPRO_OPC_NONE, BITFIELD(17, 5) /* index 993 */, - TILE_OPC_NONE, TILE_OPC_RLI, TILE_OPC_SHLIB, TILE_OPC_SHLIH, TILE_OPC_SHLI, - TILE_OPC_SHRIB, TILE_OPC_SHRIH, TILE_OPC_SHRI, TILE_OPC_SRAIB, - TILE_OPC_SRAIH, TILE_OPC_SRAI, CHILD(1026), TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_RLI, TILEPRO_OPC_SHLIB, TILEPRO_OPC_SHLIH, + TILEPRO_OPC_SHLI, TILEPRO_OPC_SHRIB, TILEPRO_OPC_SHRIH, TILEPRO_OPC_SHRI, + TILEPRO_OPC_SRAIB, TILEPRO_OPC_SRAIH, TILEPRO_OPC_SRAI, CHILD(1026), + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(12, 4) /* index 1026 */, - TILE_OPC_NONE, CHILD(1043), CHILD(1046), CHILD(1049), CHILD(1052), + TILEPRO_OPC_NONE, CHILD(1043), CHILD(1046), CHILD(1049), CHILD(1052), CHILD(1055), CHILD(1058), CHILD(1061), CHILD(1064), CHILD(1067), - CHILD(1070), CHILD(1073), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, + CHILD(1070), CHILD(1073), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1043 */, - TILE_OPC_BITX, TILE_OPC_NONE, + TILEPRO_OPC_BITX, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1046 */, - TILE_OPC_BYTEX, TILE_OPC_NONE, + TILEPRO_OPC_BYTEX, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1049 */, - TILE_OPC_CLZ, TILE_OPC_NONE, + TILEPRO_OPC_CLZ, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1052 */, - TILE_OPC_CTZ, TILE_OPC_NONE, + TILEPRO_OPC_CTZ, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1055 */, - TILE_OPC_FNOP, TILE_OPC_NONE, + TILEPRO_OPC_FNOP, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1058 */, - TILE_OPC_NOP, TILE_OPC_NONE, + TILEPRO_OPC_NOP, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1061 */, - TILE_OPC_PCNT, TILE_OPC_NONE, + TILEPRO_OPC_PCNT, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1064 */, - TILE_OPC_TBLIDXB0, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB0, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1067 */, - TILE_OPC_TBLIDXB1, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB1, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1070 */, - TILE_OPC_TBLIDXB2, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB2, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1073 */, - TILE_OPC_TBLIDXB3, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB3, TILEPRO_OPC_NONE, BITFIELD(17, 5) /* index 1076 */, - TILE_OPC_NONE, TILE_OPC_RLI_SN, TILE_OPC_SHLIB_SN, TILE_OPC_SHLIH_SN, - TILE_OPC_SHLI_SN, TILE_OPC_SHRIB_SN, TILE_OPC_SHRIH_SN, TILE_OPC_SHRI_SN, - TILE_OPC_SRAIB_SN, TILE_OPC_SRAIH_SN, TILE_OPC_SRAI_SN, CHILD(1109), - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_RLI_SN, TILEPRO_OPC_SHLIB_SN, + TILEPRO_OPC_SHLIH_SN, TILEPRO_OPC_SHLI_SN, TILEPRO_OPC_SHRIB_SN, + TILEPRO_OPC_SHRIH_SN, TILEPRO_OPC_SHRI_SN, TILEPRO_OPC_SRAIB_SN, + TILEPRO_OPC_SRAIH_SN, TILEPRO_OPC_SRAI_SN, CHILD(1109), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(12, 4) /* index 1109 */, - TILE_OPC_NONE, CHILD(1126), CHILD(1129), CHILD(1132), CHILD(1135), + TILEPRO_OPC_NONE, CHILD(1126), CHILD(1129), CHILD(1132), CHILD(1135), CHILD(1055), CHILD(1058), CHILD(1138), CHILD(1141), CHILD(1144), - CHILD(1147), CHILD(1150), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, + CHILD(1147), CHILD(1150), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1126 */, - TILE_OPC_BITX_SN, TILE_OPC_NONE, + TILEPRO_OPC_BITX_SN, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1129 */, - TILE_OPC_BYTEX_SN, TILE_OPC_NONE, + TILEPRO_OPC_BYTEX_SN, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1132 */, - TILE_OPC_CLZ_SN, TILE_OPC_NONE, + TILEPRO_OPC_CLZ_SN, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1135 */, - TILE_OPC_CTZ_SN, TILE_OPC_NONE, + TILEPRO_OPC_CTZ_SN, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1138 */, - TILE_OPC_PCNT_SN, TILE_OPC_NONE, + TILEPRO_OPC_PCNT_SN, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1141 */, - TILE_OPC_TBLIDXB0_SN, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB0_SN, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1144 */, - TILE_OPC_TBLIDXB1_SN, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB1_SN, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1147 */, - TILE_OPC_TBLIDXB2_SN, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB2_SN, TILEPRO_OPC_NONE, BITFIELD(16, 1) /* index 1150 */, - TILE_OPC_TBLIDXB3_SN, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB3_SN, TILEPRO_OPC_NONE, }; static const unsigned short decode_X1_fsm[1540] = { BITFIELD(54, 9) /* index 0 */, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, CHILD(513), CHILD(561), CHILD(594), - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(641), CHILD(689), - CHILD(722), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(766), + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + CHILD(513), CHILD(561), CHILD(594), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(641), + CHILD(689), CHILD(722), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), @@ -1596,594 +1655,641 @@ static const unsigned short decode_X1_fsm[1540] = CHILD(826), CHILD(826), CHILD(826), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(860), CHILD(899), CHILD(923), CHILD(932), TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, CHILD(941), CHILD(950), CHILD(974), CHILD(983), - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, - TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, CHILD(992), - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - CHILD(1334), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, - TILE_OPC_J, TILE_OPC_J, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, - TILE_OPC_JAL, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + CHILD(843), CHILD(860), CHILD(899), CHILD(923), CHILD(932), + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + CHILD(941), CHILD(950), CHILD(974), CHILD(983), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, + TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, CHILD(992), + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(1334), + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, + TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, + TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(49, 5) /* index 513 */, - TILE_OPC_NONE, TILE_OPC_ADDB, TILE_OPC_ADDH, TILE_OPC_ADD, TILE_OPC_AND, - TILE_OPC_INTHB, TILE_OPC_INTHH, TILE_OPC_INTLB, TILE_OPC_INTLH, - TILE_OPC_JALRP, TILE_OPC_JALR, TILE_OPC_JRP, TILE_OPC_JR, TILE_OPC_LNK, - TILE_OPC_MAXB_U, TILE_OPC_MAXH, TILE_OPC_MINB_U, TILE_OPC_MINH, - TILE_OPC_MNZB, TILE_OPC_MNZH, TILE_OPC_MNZ, TILE_OPC_MZB, TILE_OPC_MZH, - TILE_OPC_MZ, TILE_OPC_NOR, CHILD(546), TILE_OPC_PACKHB, TILE_OPC_PACKLB, - TILE_OPC_RL, TILE_OPC_S1A, TILE_OPC_S2A, TILE_OPC_S3A, + TILEPRO_OPC_NONE, TILEPRO_OPC_ADDB, TILEPRO_OPC_ADDH, TILEPRO_OPC_ADD, + TILEPRO_OPC_AND, TILEPRO_OPC_INTHB, TILEPRO_OPC_INTHH, TILEPRO_OPC_INTLB, + TILEPRO_OPC_INTLH, TILEPRO_OPC_JALRP, TILEPRO_OPC_JALR, TILEPRO_OPC_JRP, + TILEPRO_OPC_JR, TILEPRO_OPC_LNK, TILEPRO_OPC_MAXB_U, TILEPRO_OPC_MAXH, + TILEPRO_OPC_MINB_U, TILEPRO_OPC_MINH, TILEPRO_OPC_MNZB, TILEPRO_OPC_MNZH, + TILEPRO_OPC_MNZ, TILEPRO_OPC_MZB, TILEPRO_OPC_MZH, TILEPRO_OPC_MZ, + TILEPRO_OPC_NOR, CHILD(546), TILEPRO_OPC_PACKHB, TILEPRO_OPC_PACKLB, + TILEPRO_OPC_RL, TILEPRO_OPC_S1A, TILEPRO_OPC_S2A, TILEPRO_OPC_S3A, BITFIELD(43, 2) /* index 546 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(551), + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(551), BITFIELD(45, 2) /* index 551 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(556), + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(556), BITFIELD(47, 2) /* index 556 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_MOVE, + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_MOVE, BITFIELD(49, 5) /* index 561 */, - TILE_OPC_SB, TILE_OPC_SEQB, TILE_OPC_SEQH, TILE_OPC_SEQ, TILE_OPC_SHLB, - TILE_OPC_SHLH, TILE_OPC_SHL, TILE_OPC_SHRB, TILE_OPC_SHRH, TILE_OPC_SHR, - TILE_OPC_SH, TILE_OPC_SLTB, TILE_OPC_SLTB_U, TILE_OPC_SLTEB, - TILE_OPC_SLTEB_U, TILE_OPC_SLTEH, TILE_OPC_SLTEH_U, TILE_OPC_SLTE, - TILE_OPC_SLTE_U, TILE_OPC_SLTH, TILE_OPC_SLTH_U, TILE_OPC_SLT, - TILE_OPC_SLT_U, TILE_OPC_SNEB, TILE_OPC_SNEH, TILE_OPC_SNE, TILE_OPC_SRAB, - TILE_OPC_SRAH, TILE_OPC_SRA, TILE_OPC_SUBB, TILE_OPC_SUBH, TILE_OPC_SUB, + TILEPRO_OPC_SB, TILEPRO_OPC_SEQB, TILEPRO_OPC_SEQH, TILEPRO_OPC_SEQ, + TILEPRO_OPC_SHLB, TILEPRO_OPC_SHLH, TILEPRO_OPC_SHL, TILEPRO_OPC_SHRB, + TILEPRO_OPC_SHRH, TILEPRO_OPC_SHR, TILEPRO_OPC_SH, TILEPRO_OPC_SLTB, + TILEPRO_OPC_SLTB_U, TILEPRO_OPC_SLTEB, TILEPRO_OPC_SLTEB_U, + TILEPRO_OPC_SLTEH, TILEPRO_OPC_SLTEH_U, TILEPRO_OPC_SLTE, + TILEPRO_OPC_SLTE_U, TILEPRO_OPC_SLTH, TILEPRO_OPC_SLTH_U, TILEPRO_OPC_SLT, + TILEPRO_OPC_SLT_U, TILEPRO_OPC_SNEB, TILEPRO_OPC_SNEH, TILEPRO_OPC_SNE, + TILEPRO_OPC_SRAB, TILEPRO_OPC_SRAH, TILEPRO_OPC_SRA, TILEPRO_OPC_SUBB, + TILEPRO_OPC_SUBH, TILEPRO_OPC_SUB, BITFIELD(49, 4) /* index 594 */, CHILD(611), CHILD(614), CHILD(617), CHILD(620), CHILD(623), CHILD(626), - CHILD(629), CHILD(632), CHILD(635), CHILD(638), TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + CHILD(629), CHILD(632), CHILD(635), CHILD(638), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 611 */, - TILE_OPC_SW, TILE_OPC_NONE, + TILEPRO_OPC_SW, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 614 */, - TILE_OPC_XOR, TILE_OPC_NONE, + TILEPRO_OPC_XOR, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 617 */, - TILE_OPC_ADDS, TILE_OPC_NONE, + TILEPRO_OPC_ADDS, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 620 */, - TILE_OPC_SUBS, TILE_OPC_NONE, + TILEPRO_OPC_SUBS, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 623 */, - TILE_OPC_ADDBS_U, TILE_OPC_NONE, + TILEPRO_OPC_ADDBS_U, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 626 */, - TILE_OPC_ADDHS, TILE_OPC_NONE, + TILEPRO_OPC_ADDHS, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 629 */, - TILE_OPC_SUBBS_U, TILE_OPC_NONE, + TILEPRO_OPC_SUBBS_U, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 632 */, - TILE_OPC_SUBHS, TILE_OPC_NONE, + TILEPRO_OPC_SUBHS, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 635 */, - TILE_OPC_PACKHS, TILE_OPC_NONE, + TILEPRO_OPC_PACKHS, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 638 */, - TILE_OPC_PACKBS_U, TILE_OPC_NONE, + TILEPRO_OPC_PACKBS_U, TILEPRO_OPC_NONE, BITFIELD(49, 5) /* index 641 */, - TILE_OPC_NONE, TILE_OPC_ADDB_SN, TILE_OPC_ADDH_SN, TILE_OPC_ADD_SN, - TILE_OPC_AND_SN, TILE_OPC_INTHB_SN, TILE_OPC_INTHH_SN, TILE_OPC_INTLB_SN, - TILE_OPC_INTLH_SN, TILE_OPC_JALRP, TILE_OPC_JALR, TILE_OPC_JRP, TILE_OPC_JR, - TILE_OPC_LNK_SN, TILE_OPC_MAXB_U_SN, TILE_OPC_MAXH_SN, TILE_OPC_MINB_U_SN, - TILE_OPC_MINH_SN, TILE_OPC_MNZB_SN, TILE_OPC_MNZH_SN, TILE_OPC_MNZ_SN, - TILE_OPC_MZB_SN, TILE_OPC_MZH_SN, TILE_OPC_MZ_SN, TILE_OPC_NOR_SN, - CHILD(674), TILE_OPC_PACKHB_SN, TILE_OPC_PACKLB_SN, TILE_OPC_RL_SN, - TILE_OPC_S1A_SN, TILE_OPC_S2A_SN, TILE_OPC_S3A_SN, + TILEPRO_OPC_NONE, TILEPRO_OPC_ADDB_SN, TILEPRO_OPC_ADDH_SN, + TILEPRO_OPC_ADD_SN, TILEPRO_OPC_AND_SN, TILEPRO_OPC_INTHB_SN, + TILEPRO_OPC_INTHH_SN, TILEPRO_OPC_INTLB_SN, TILEPRO_OPC_INTLH_SN, + TILEPRO_OPC_JALRP, TILEPRO_OPC_JALR, TILEPRO_OPC_JRP, TILEPRO_OPC_JR, + TILEPRO_OPC_LNK_SN, TILEPRO_OPC_MAXB_U_SN, TILEPRO_OPC_MAXH_SN, + TILEPRO_OPC_MINB_U_SN, TILEPRO_OPC_MINH_SN, TILEPRO_OPC_MNZB_SN, + TILEPRO_OPC_MNZH_SN, TILEPRO_OPC_MNZ_SN, TILEPRO_OPC_MZB_SN, + TILEPRO_OPC_MZH_SN, TILEPRO_OPC_MZ_SN, TILEPRO_OPC_NOR_SN, CHILD(674), + TILEPRO_OPC_PACKHB_SN, TILEPRO_OPC_PACKLB_SN, TILEPRO_OPC_RL_SN, + TILEPRO_OPC_S1A_SN, TILEPRO_OPC_S2A_SN, TILEPRO_OPC_S3A_SN, BITFIELD(43, 2) /* index 674 */, - TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, CHILD(679), + TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, CHILD(679), BITFIELD(45, 2) /* index 679 */, - TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, CHILD(684), + TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, CHILD(684), BITFIELD(47, 2) /* index 684 */, - TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_MOVE_SN, + TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, + TILEPRO_OPC_MOVE_SN, BITFIELD(49, 5) /* index 689 */, - TILE_OPC_SB, TILE_OPC_SEQB_SN, TILE_OPC_SEQH_SN, TILE_OPC_SEQ_SN, - TILE_OPC_SHLB_SN, TILE_OPC_SHLH_SN, TILE_OPC_SHL_SN, TILE_OPC_SHRB_SN, - TILE_OPC_SHRH_SN, TILE_OPC_SHR_SN, TILE_OPC_SH, TILE_OPC_SLTB_SN, - TILE_OPC_SLTB_U_SN, TILE_OPC_SLTEB_SN, TILE_OPC_SLTEB_U_SN, - TILE_OPC_SLTEH_SN, TILE_OPC_SLTEH_U_SN, TILE_OPC_SLTE_SN, - TILE_OPC_SLTE_U_SN, TILE_OPC_SLTH_SN, TILE_OPC_SLTH_U_SN, TILE_OPC_SLT_SN, - TILE_OPC_SLT_U_SN, TILE_OPC_SNEB_SN, TILE_OPC_SNEH_SN, TILE_OPC_SNE_SN, - TILE_OPC_SRAB_SN, TILE_OPC_SRAH_SN, TILE_OPC_SRA_SN, TILE_OPC_SUBB_SN, - TILE_OPC_SUBH_SN, TILE_OPC_SUB_SN, + TILEPRO_OPC_SB, TILEPRO_OPC_SEQB_SN, TILEPRO_OPC_SEQH_SN, + TILEPRO_OPC_SEQ_SN, TILEPRO_OPC_SHLB_SN, TILEPRO_OPC_SHLH_SN, + TILEPRO_OPC_SHL_SN, TILEPRO_OPC_SHRB_SN, TILEPRO_OPC_SHRH_SN, + TILEPRO_OPC_SHR_SN, TILEPRO_OPC_SH, TILEPRO_OPC_SLTB_SN, + TILEPRO_OPC_SLTB_U_SN, TILEPRO_OPC_SLTEB_SN, TILEPRO_OPC_SLTEB_U_SN, + TILEPRO_OPC_SLTEH_SN, TILEPRO_OPC_SLTEH_U_SN, TILEPRO_OPC_SLTE_SN, + TILEPRO_OPC_SLTE_U_SN, TILEPRO_OPC_SLTH_SN, TILEPRO_OPC_SLTH_U_SN, + TILEPRO_OPC_SLT_SN, TILEPRO_OPC_SLT_U_SN, TILEPRO_OPC_SNEB_SN, + TILEPRO_OPC_SNEH_SN, TILEPRO_OPC_SNE_SN, TILEPRO_OPC_SRAB_SN, + TILEPRO_OPC_SRAH_SN, TILEPRO_OPC_SRA_SN, TILEPRO_OPC_SUBB_SN, + TILEPRO_OPC_SUBH_SN, TILEPRO_OPC_SUB_SN, BITFIELD(49, 4) /* index 722 */, CHILD(611), CHILD(739), CHILD(742), CHILD(745), CHILD(748), CHILD(751), - CHILD(754), CHILD(757), CHILD(760), CHILD(763), TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + CHILD(754), CHILD(757), CHILD(760), CHILD(763), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 739 */, - TILE_OPC_XOR_SN, TILE_OPC_NONE, + TILEPRO_OPC_XOR_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 742 */, - TILE_OPC_ADDS_SN, TILE_OPC_NONE, + TILEPRO_OPC_ADDS_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 745 */, - TILE_OPC_SUBS_SN, TILE_OPC_NONE, + TILEPRO_OPC_SUBS_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 748 */, - TILE_OPC_ADDBS_U_SN, TILE_OPC_NONE, + TILEPRO_OPC_ADDBS_U_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 751 */, - TILE_OPC_ADDHS_SN, TILE_OPC_NONE, + TILEPRO_OPC_ADDHS_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 754 */, - TILE_OPC_SUBBS_U_SN, TILE_OPC_NONE, + TILEPRO_OPC_SUBBS_U_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 757 */, - TILE_OPC_SUBHS_SN, TILE_OPC_NONE, + TILEPRO_OPC_SUBHS_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 760 */, - TILE_OPC_PACKHS_SN, TILE_OPC_NONE, + TILEPRO_OPC_PACKHS_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 763 */, - TILE_OPC_PACKBS_U_SN, TILE_OPC_NONE, + TILEPRO_OPC_PACKBS_U_SN, TILEPRO_OPC_NONE, BITFIELD(37, 2) /* index 766 */, - TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, CHILD(771), + TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, + CHILD(771), BITFIELD(39, 2) /* index 771 */, - TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, CHILD(776), + TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, + CHILD(776), BITFIELD(41, 2) /* index 776 */, - TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_MOVELI_SN, + TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, + TILEPRO_OPC_MOVELI_SN, BITFIELD(37, 2) /* index 781 */, - TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, CHILD(786), + TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, CHILD(786), BITFIELD(39, 2) /* index 786 */, - TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, CHILD(791), + TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, CHILD(791), BITFIELD(41, 2) /* index 791 */, - TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_MOVELI, + TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_MOVELI, BITFIELD(31, 2) /* index 796 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(801), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(801), BITFIELD(33, 2) /* index 801 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(806), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(806), BITFIELD(35, 2) /* index 806 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(811), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(811), BITFIELD(37, 2) /* index 811 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(816), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(816), BITFIELD(39, 2) /* index 816 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(821), + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(821), BITFIELD(41, 2) /* index 821 */, - TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_INFOL, + TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_INFOL, BITFIELD(31, 4) /* index 826 */, - TILE_OPC_BZ, TILE_OPC_BZT, TILE_OPC_BNZ, TILE_OPC_BNZT, TILE_OPC_BGZ, - TILE_OPC_BGZT, TILE_OPC_BGEZ, TILE_OPC_BGEZT, TILE_OPC_BLZ, TILE_OPC_BLZT, - TILE_OPC_BLEZ, TILE_OPC_BLEZT, TILE_OPC_BBS, TILE_OPC_BBST, TILE_OPC_BBNS, - TILE_OPC_BBNST, + TILEPRO_OPC_BZ, TILEPRO_OPC_BZT, TILEPRO_OPC_BNZ, TILEPRO_OPC_BNZT, + TILEPRO_OPC_BGZ, TILEPRO_OPC_BGZT, TILEPRO_OPC_BGEZ, TILEPRO_OPC_BGEZT, + TILEPRO_OPC_BLZ, TILEPRO_OPC_BLZT, TILEPRO_OPC_BLEZ, TILEPRO_OPC_BLEZT, + TILEPRO_OPC_BBS, TILEPRO_OPC_BBST, TILEPRO_OPC_BBNS, TILEPRO_OPC_BBNST, BITFIELD(31, 4) /* index 843 */, - TILE_OPC_BZ_SN, TILE_OPC_BZT_SN, TILE_OPC_BNZ_SN, TILE_OPC_BNZT_SN, - TILE_OPC_BGZ_SN, TILE_OPC_BGZT_SN, TILE_OPC_BGEZ_SN, TILE_OPC_BGEZT_SN, - TILE_OPC_BLZ_SN, TILE_OPC_BLZT_SN, TILE_OPC_BLEZ_SN, TILE_OPC_BLEZT_SN, - TILE_OPC_BBS_SN, TILE_OPC_BBST_SN, TILE_OPC_BBNS_SN, TILE_OPC_BBNST_SN, + TILEPRO_OPC_BZ_SN, TILEPRO_OPC_BZT_SN, TILEPRO_OPC_BNZ_SN, + TILEPRO_OPC_BNZT_SN, TILEPRO_OPC_BGZ_SN, TILEPRO_OPC_BGZT_SN, + TILEPRO_OPC_BGEZ_SN, TILEPRO_OPC_BGEZT_SN, TILEPRO_OPC_BLZ_SN, + TILEPRO_OPC_BLZT_SN, TILEPRO_OPC_BLEZ_SN, TILEPRO_OPC_BLEZT_SN, + TILEPRO_OPC_BBS_SN, TILEPRO_OPC_BBST_SN, TILEPRO_OPC_BBNS_SN, + TILEPRO_OPC_BBNST_SN, BITFIELD(51, 3) /* index 860 */, - TILE_OPC_NONE, TILE_OPC_ADDIB, TILE_OPC_ADDIH, TILE_OPC_ADDI, CHILD(869), - TILE_OPC_MAXIB_U, TILE_OPC_MAXIH, TILE_OPC_MFSPR, + TILEPRO_OPC_NONE, TILEPRO_OPC_ADDIB, TILEPRO_OPC_ADDIH, TILEPRO_OPC_ADDI, + CHILD(869), TILEPRO_OPC_MAXIB_U, TILEPRO_OPC_MAXIH, TILEPRO_OPC_MFSPR, BITFIELD(31, 2) /* index 869 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(874), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(874), BITFIELD(33, 2) /* index 874 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(879), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(879), BITFIELD(35, 2) /* index 879 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(884), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(884), BITFIELD(37, 2) /* index 884 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(889), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(889), BITFIELD(39, 2) /* index 889 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(894), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(894), BITFIELD(41, 2) /* index 894 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_INFO, + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_INFO, BITFIELD(51, 3) /* index 899 */, - TILE_OPC_MINIB_U, TILE_OPC_MINIH, TILE_OPC_MTSPR, CHILD(908), - TILE_OPC_SEQIB, TILE_OPC_SEQIH, TILE_OPC_SEQI, TILE_OPC_SLTIB, + TILEPRO_OPC_MINIB_U, TILEPRO_OPC_MINIH, TILEPRO_OPC_MTSPR, CHILD(908), + TILEPRO_OPC_SEQIB, TILEPRO_OPC_SEQIH, TILEPRO_OPC_SEQI, TILEPRO_OPC_SLTIB, BITFIELD(37, 2) /* index 908 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(913), + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(913), BITFIELD(39, 2) /* index 913 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(918), + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(918), BITFIELD(41, 2) /* index 918 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_MOVEI, + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_MOVEI, BITFIELD(51, 3) /* index 923 */, - TILE_OPC_SLTIB_U, TILE_OPC_SLTIH, TILE_OPC_SLTIH_U, TILE_OPC_SLTI, - TILE_OPC_SLTI_U, TILE_OPC_XORI, TILE_OPC_LBADD, TILE_OPC_LBADD_U, + TILEPRO_OPC_SLTIB_U, TILEPRO_OPC_SLTIH, TILEPRO_OPC_SLTIH_U, + TILEPRO_OPC_SLTI, TILEPRO_OPC_SLTI_U, TILEPRO_OPC_XORI, TILEPRO_OPC_LBADD, + TILEPRO_OPC_LBADD_U, BITFIELD(51, 3) /* index 932 */, - TILE_OPC_LHADD, TILE_OPC_LHADD_U, TILE_OPC_LWADD, TILE_OPC_LWADD_NA, - TILE_OPC_SBADD, TILE_OPC_SHADD, TILE_OPC_SWADD, TILE_OPC_NONE, + TILEPRO_OPC_LHADD, TILEPRO_OPC_LHADD_U, TILEPRO_OPC_LWADD, + TILEPRO_OPC_LWADD_NA, TILEPRO_OPC_SBADD, TILEPRO_OPC_SHADD, + TILEPRO_OPC_SWADD, TILEPRO_OPC_NONE, BITFIELD(51, 3) /* index 941 */, - TILE_OPC_NONE, TILE_OPC_ADDIB_SN, TILE_OPC_ADDIH_SN, TILE_OPC_ADDI_SN, - TILE_OPC_ANDI_SN, TILE_OPC_MAXIB_U_SN, TILE_OPC_MAXIH_SN, TILE_OPC_MFSPR, + TILEPRO_OPC_NONE, TILEPRO_OPC_ADDIB_SN, TILEPRO_OPC_ADDIH_SN, + TILEPRO_OPC_ADDI_SN, TILEPRO_OPC_ANDI_SN, TILEPRO_OPC_MAXIB_U_SN, + TILEPRO_OPC_MAXIH_SN, TILEPRO_OPC_MFSPR, BITFIELD(51, 3) /* index 950 */, - TILE_OPC_MINIB_U_SN, TILE_OPC_MINIH_SN, TILE_OPC_MTSPR, CHILD(959), - TILE_OPC_SEQIB_SN, TILE_OPC_SEQIH_SN, TILE_OPC_SEQI_SN, TILE_OPC_SLTIB_SN, + TILEPRO_OPC_MINIB_U_SN, TILEPRO_OPC_MINIH_SN, TILEPRO_OPC_MTSPR, CHILD(959), + TILEPRO_OPC_SEQIB_SN, TILEPRO_OPC_SEQIH_SN, TILEPRO_OPC_SEQI_SN, + TILEPRO_OPC_SLTIB_SN, BITFIELD(37, 2) /* index 959 */, - TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, CHILD(964), + TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, CHILD(964), BITFIELD(39, 2) /* index 964 */, - TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, CHILD(969), + TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, CHILD(969), BITFIELD(41, 2) /* index 969 */, - TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_MOVEI_SN, + TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, + TILEPRO_OPC_MOVEI_SN, BITFIELD(51, 3) /* index 974 */, - TILE_OPC_SLTIB_U_SN, TILE_OPC_SLTIH_SN, TILE_OPC_SLTIH_U_SN, - TILE_OPC_SLTI_SN, TILE_OPC_SLTI_U_SN, TILE_OPC_XORI_SN, TILE_OPC_LBADD_SN, - TILE_OPC_LBADD_U_SN, + TILEPRO_OPC_SLTIB_U_SN, TILEPRO_OPC_SLTIH_SN, TILEPRO_OPC_SLTIH_U_SN, + TILEPRO_OPC_SLTI_SN, TILEPRO_OPC_SLTI_U_SN, TILEPRO_OPC_XORI_SN, + TILEPRO_OPC_LBADD_SN, TILEPRO_OPC_LBADD_U_SN, BITFIELD(51, 3) /* index 983 */, - TILE_OPC_LHADD_SN, TILE_OPC_LHADD_U_SN, TILE_OPC_LWADD_SN, - TILE_OPC_LWADD_NA_SN, TILE_OPC_SBADD, TILE_OPC_SHADD, TILE_OPC_SWADD, - TILE_OPC_NONE, + TILEPRO_OPC_LHADD_SN, TILEPRO_OPC_LHADD_U_SN, TILEPRO_OPC_LWADD_SN, + TILEPRO_OPC_LWADD_NA_SN, TILEPRO_OPC_SBADD, TILEPRO_OPC_SHADD, + TILEPRO_OPC_SWADD, TILEPRO_OPC_NONE, BITFIELD(46, 7) /* index 992 */, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(1121), - CHILD(1121), CHILD(1121), CHILD(1121), CHILD(1124), CHILD(1124), - CHILD(1124), CHILD(1124), CHILD(1127), CHILD(1127), CHILD(1127), - CHILD(1127), CHILD(1130), CHILD(1130), CHILD(1130), CHILD(1130), - CHILD(1133), CHILD(1133), CHILD(1133), CHILD(1133), CHILD(1136), - CHILD(1136), CHILD(1136), CHILD(1136), CHILD(1139), CHILD(1139), - CHILD(1139), CHILD(1139), CHILD(1142), CHILD(1142), CHILD(1142), - CHILD(1142), CHILD(1145), CHILD(1145), CHILD(1145), CHILD(1145), - CHILD(1148), CHILD(1148), CHILD(1148), CHILD(1148), CHILD(1151), - CHILD(1242), CHILD(1290), CHILD(1323), TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + CHILD(1121), CHILD(1121), CHILD(1121), CHILD(1121), CHILD(1124), + CHILD(1124), CHILD(1124), CHILD(1124), CHILD(1127), CHILD(1127), + CHILD(1127), CHILD(1127), CHILD(1130), CHILD(1130), CHILD(1130), + CHILD(1130), CHILD(1133), CHILD(1133), CHILD(1133), CHILD(1133), + CHILD(1136), CHILD(1136), CHILD(1136), CHILD(1136), CHILD(1139), + CHILD(1139), CHILD(1139), CHILD(1139), CHILD(1142), CHILD(1142), + CHILD(1142), CHILD(1142), CHILD(1145), CHILD(1145), CHILD(1145), + CHILD(1145), CHILD(1148), CHILD(1148), CHILD(1148), CHILD(1148), + CHILD(1151), CHILD(1242), CHILD(1290), CHILD(1323), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1121 */, - TILE_OPC_RLI, TILE_OPC_NONE, + TILEPRO_OPC_RLI, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1124 */, - TILE_OPC_SHLIB, TILE_OPC_NONE, + TILEPRO_OPC_SHLIB, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1127 */, - TILE_OPC_SHLIH, TILE_OPC_NONE, + TILEPRO_OPC_SHLIH, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1130 */, - TILE_OPC_SHLI, TILE_OPC_NONE, + TILEPRO_OPC_SHLI, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1133 */, - TILE_OPC_SHRIB, TILE_OPC_NONE, + TILEPRO_OPC_SHRIB, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1136 */, - TILE_OPC_SHRIH, TILE_OPC_NONE, + TILEPRO_OPC_SHRIH, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1139 */, - TILE_OPC_SHRI, TILE_OPC_NONE, + TILEPRO_OPC_SHRI, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1142 */, - TILE_OPC_SRAIB, TILE_OPC_NONE, + TILEPRO_OPC_SRAIB, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1145 */, - TILE_OPC_SRAIH, TILE_OPC_NONE, + TILEPRO_OPC_SRAIH, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1148 */, - TILE_OPC_SRAI, TILE_OPC_NONE, + TILEPRO_OPC_SRAI, TILEPRO_OPC_NONE, BITFIELD(43, 3) /* index 1151 */, - TILE_OPC_NONE, CHILD(1160), CHILD(1163), CHILD(1166), CHILD(1169), + TILEPRO_OPC_NONE, CHILD(1160), CHILD(1163), CHILD(1166), CHILD(1169), CHILD(1172), CHILD(1175), CHILD(1178), BITFIELD(53, 1) /* index 1160 */, - TILE_OPC_DRAIN, TILE_OPC_NONE, + TILEPRO_OPC_DRAIN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1163 */, - TILE_OPC_DTLBPR, TILE_OPC_NONE, + TILEPRO_OPC_DTLBPR, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1166 */, - TILE_OPC_FINV, TILE_OPC_NONE, + TILEPRO_OPC_FINV, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1169 */, - TILE_OPC_FLUSH, TILE_OPC_NONE, + TILEPRO_OPC_FLUSH, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1172 */, - TILE_OPC_FNOP, TILE_OPC_NONE, + TILEPRO_OPC_FNOP, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1175 */, - TILE_OPC_ICOH, TILE_OPC_NONE, + TILEPRO_OPC_ICOH, TILEPRO_OPC_NONE, BITFIELD(31, 2) /* index 1178 */, CHILD(1183), CHILD(1211), CHILD(1239), CHILD(1239), BITFIELD(53, 1) /* index 1183 */, - CHILD(1186), TILE_OPC_NONE, + CHILD(1186), TILEPRO_OPC_NONE, BITFIELD(33, 2) /* index 1186 */, - TILE_OPC_ILL, TILE_OPC_ILL, TILE_OPC_ILL, CHILD(1191), + TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, CHILD(1191), BITFIELD(35, 2) /* index 1191 */, - TILE_OPC_ILL, CHILD(1196), TILE_OPC_ILL, TILE_OPC_ILL, + TILEPRO_OPC_ILL, CHILD(1196), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, BITFIELD(37, 2) /* index 1196 */, - TILE_OPC_ILL, CHILD(1201), TILE_OPC_ILL, TILE_OPC_ILL, + TILEPRO_OPC_ILL, CHILD(1201), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, BITFIELD(39, 2) /* index 1201 */, - TILE_OPC_ILL, CHILD(1206), TILE_OPC_ILL, TILE_OPC_ILL, + TILEPRO_OPC_ILL, CHILD(1206), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, BITFIELD(41, 2) /* index 1206 */, - TILE_OPC_ILL, TILE_OPC_ILL, TILE_OPC_BPT, TILE_OPC_ILL, + TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, TILEPRO_OPC_BPT, TILEPRO_OPC_ILL, BITFIELD(53, 1) /* index 1211 */, - CHILD(1214), TILE_OPC_NONE, + CHILD(1214), TILEPRO_OPC_NONE, BITFIELD(33, 2) /* index 1214 */, - TILE_OPC_ILL, TILE_OPC_ILL, TILE_OPC_ILL, CHILD(1219), + TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, CHILD(1219), BITFIELD(35, 2) /* index 1219 */, - TILE_OPC_ILL, CHILD(1224), TILE_OPC_ILL, TILE_OPC_ILL, + TILEPRO_OPC_ILL, CHILD(1224), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, BITFIELD(37, 2) /* index 1224 */, - TILE_OPC_ILL, CHILD(1229), TILE_OPC_ILL, TILE_OPC_ILL, + TILEPRO_OPC_ILL, CHILD(1229), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, BITFIELD(39, 2) /* index 1229 */, - TILE_OPC_ILL, CHILD(1234), TILE_OPC_ILL, TILE_OPC_ILL, + TILEPRO_OPC_ILL, CHILD(1234), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, BITFIELD(41, 2) /* index 1234 */, - TILE_OPC_ILL, TILE_OPC_ILL, TILE_OPC_RAISE, TILE_OPC_ILL, + TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, TILEPRO_OPC_RAISE, TILEPRO_OPC_ILL, BITFIELD(53, 1) /* index 1239 */, - TILE_OPC_ILL, TILE_OPC_NONE, + TILEPRO_OPC_ILL, TILEPRO_OPC_NONE, BITFIELD(43, 3) /* index 1242 */, CHILD(1251), CHILD(1254), CHILD(1257), CHILD(1275), CHILD(1278), CHILD(1281), CHILD(1284), CHILD(1287), BITFIELD(53, 1) /* index 1251 */, - TILE_OPC_INV, TILE_OPC_NONE, + TILEPRO_OPC_INV, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1254 */, - TILE_OPC_IRET, TILE_OPC_NONE, + TILEPRO_OPC_IRET, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1257 */, - CHILD(1260), TILE_OPC_NONE, + CHILD(1260), TILEPRO_OPC_NONE, BITFIELD(31, 2) /* index 1260 */, - TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, CHILD(1265), + TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, CHILD(1265), BITFIELD(33, 2) /* index 1265 */, - TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, CHILD(1270), + TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, CHILD(1270), BITFIELD(35, 2) /* index 1270 */, - TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_PREFETCH, + TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_PREFETCH, BITFIELD(53, 1) /* index 1275 */, - TILE_OPC_LB_U, TILE_OPC_NONE, + TILEPRO_OPC_LB_U, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1278 */, - TILE_OPC_LH, TILE_OPC_NONE, + TILEPRO_OPC_LH, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1281 */, - TILE_OPC_LH_U, TILE_OPC_NONE, + TILEPRO_OPC_LH_U, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1284 */, - TILE_OPC_LW, TILE_OPC_NONE, + TILEPRO_OPC_LW, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1287 */, - TILE_OPC_MF, TILE_OPC_NONE, + TILEPRO_OPC_MF, TILEPRO_OPC_NONE, BITFIELD(43, 3) /* index 1290 */, CHILD(1299), CHILD(1302), CHILD(1305), CHILD(1308), CHILD(1311), CHILD(1314), CHILD(1317), CHILD(1320), BITFIELD(53, 1) /* index 1299 */, - TILE_OPC_NAP, TILE_OPC_NONE, + TILEPRO_OPC_NAP, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1302 */, - TILE_OPC_NOP, TILE_OPC_NONE, + TILEPRO_OPC_NOP, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1305 */, - TILE_OPC_SWINT0, TILE_OPC_NONE, + TILEPRO_OPC_SWINT0, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1308 */, - TILE_OPC_SWINT1, TILE_OPC_NONE, + TILEPRO_OPC_SWINT1, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1311 */, - TILE_OPC_SWINT2, TILE_OPC_NONE, + TILEPRO_OPC_SWINT2, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1314 */, - TILE_OPC_SWINT3, TILE_OPC_NONE, + TILEPRO_OPC_SWINT3, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1317 */, - TILE_OPC_TNS, TILE_OPC_NONE, + TILEPRO_OPC_TNS, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1320 */, - TILE_OPC_WH64, TILE_OPC_NONE, + TILEPRO_OPC_WH64, TILEPRO_OPC_NONE, BITFIELD(43, 2) /* index 1323 */, - CHILD(1328), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + CHILD(1328), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(45, 1) /* index 1328 */, - CHILD(1331), TILE_OPC_NONE, + CHILD(1331), TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1331 */, - TILE_OPC_LW_NA, TILE_OPC_NONE, + TILEPRO_OPC_LW_NA, TILEPRO_OPC_NONE, BITFIELD(46, 7) /* index 1334 */, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(1463), - CHILD(1463), CHILD(1463), CHILD(1463), CHILD(1466), CHILD(1466), - CHILD(1466), CHILD(1466), CHILD(1469), CHILD(1469), CHILD(1469), - CHILD(1469), CHILD(1472), CHILD(1472), CHILD(1472), CHILD(1472), - CHILD(1475), CHILD(1475), CHILD(1475), CHILD(1475), CHILD(1478), - CHILD(1478), CHILD(1478), CHILD(1478), CHILD(1481), CHILD(1481), - CHILD(1481), CHILD(1481), CHILD(1484), CHILD(1484), CHILD(1484), - CHILD(1484), CHILD(1487), CHILD(1487), CHILD(1487), CHILD(1487), - CHILD(1490), CHILD(1490), CHILD(1490), CHILD(1490), CHILD(1151), - CHILD(1493), CHILD(1517), CHILD(1529), TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + CHILD(1463), CHILD(1463), CHILD(1463), CHILD(1463), CHILD(1466), + CHILD(1466), CHILD(1466), CHILD(1466), CHILD(1469), CHILD(1469), + CHILD(1469), CHILD(1469), CHILD(1472), CHILD(1472), CHILD(1472), + CHILD(1472), CHILD(1475), CHILD(1475), CHILD(1475), CHILD(1475), + CHILD(1478), CHILD(1478), CHILD(1478), CHILD(1478), CHILD(1481), + CHILD(1481), CHILD(1481), CHILD(1481), CHILD(1484), CHILD(1484), + CHILD(1484), CHILD(1484), CHILD(1487), CHILD(1487), CHILD(1487), + CHILD(1487), CHILD(1490), CHILD(1490), CHILD(1490), CHILD(1490), + CHILD(1151), CHILD(1493), CHILD(1517), CHILD(1529), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1463 */, - TILE_OPC_RLI_SN, TILE_OPC_NONE, + TILEPRO_OPC_RLI_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1466 */, - TILE_OPC_SHLIB_SN, TILE_OPC_NONE, + TILEPRO_OPC_SHLIB_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1469 */, - TILE_OPC_SHLIH_SN, TILE_OPC_NONE, + TILEPRO_OPC_SHLIH_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1472 */, - TILE_OPC_SHLI_SN, TILE_OPC_NONE, + TILEPRO_OPC_SHLI_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1475 */, - TILE_OPC_SHRIB_SN, TILE_OPC_NONE, + TILEPRO_OPC_SHRIB_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1478 */, - TILE_OPC_SHRIH_SN, TILE_OPC_NONE, + TILEPRO_OPC_SHRIH_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1481 */, - TILE_OPC_SHRI_SN, TILE_OPC_NONE, + TILEPRO_OPC_SHRI_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1484 */, - TILE_OPC_SRAIB_SN, TILE_OPC_NONE, + TILEPRO_OPC_SRAIB_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1487 */, - TILE_OPC_SRAIH_SN, TILE_OPC_NONE, + TILEPRO_OPC_SRAIH_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1490 */, - TILE_OPC_SRAI_SN, TILE_OPC_NONE, + TILEPRO_OPC_SRAI_SN, TILEPRO_OPC_NONE, BITFIELD(43, 3) /* index 1493 */, CHILD(1251), CHILD(1254), CHILD(1502), CHILD(1505), CHILD(1508), CHILD(1511), CHILD(1514), CHILD(1287), BITFIELD(53, 1) /* index 1502 */, - TILE_OPC_LB_SN, TILE_OPC_NONE, + TILEPRO_OPC_LB_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1505 */, - TILE_OPC_LB_U_SN, TILE_OPC_NONE, + TILEPRO_OPC_LB_U_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1508 */, - TILE_OPC_LH_SN, TILE_OPC_NONE, + TILEPRO_OPC_LH_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1511 */, - TILE_OPC_LH_U_SN, TILE_OPC_NONE, + TILEPRO_OPC_LH_U_SN, TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1514 */, - TILE_OPC_LW_SN, TILE_OPC_NONE, + TILEPRO_OPC_LW_SN, TILEPRO_OPC_NONE, BITFIELD(43, 3) /* index 1517 */, CHILD(1299), CHILD(1302), CHILD(1305), CHILD(1308), CHILD(1311), CHILD(1314), CHILD(1526), CHILD(1320), BITFIELD(53, 1) /* index 1526 */, - TILE_OPC_TNS_SN, TILE_OPC_NONE, + TILEPRO_OPC_TNS_SN, TILEPRO_OPC_NONE, BITFIELD(43, 2) /* index 1529 */, - CHILD(1534), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + CHILD(1534), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(45, 1) /* index 1534 */, - CHILD(1537), TILE_OPC_NONE, + CHILD(1537), TILEPRO_OPC_NONE, BITFIELD(53, 1) /* index 1537 */, - TILE_OPC_LW_NA_SN, TILE_OPC_NONE, + TILEPRO_OPC_LW_NA_SN, TILEPRO_OPC_NONE, }; static const unsigned short decode_Y0_fsm[168] = { BITFIELD(27, 4) /* index 0 */, - TILE_OPC_NONE, CHILD(17), CHILD(22), CHILD(27), CHILD(47), CHILD(52), - CHILD(57), CHILD(62), CHILD(67), TILE_OPC_ADDI, CHILD(72), CHILD(102), - TILE_OPC_SEQI, CHILD(117), TILE_OPC_SLTI, TILE_OPC_SLTI_U, + TILEPRO_OPC_NONE, CHILD(17), CHILD(22), CHILD(27), CHILD(47), CHILD(52), + CHILD(57), CHILD(62), CHILD(67), TILEPRO_OPC_ADDI, CHILD(72), CHILD(102), + TILEPRO_OPC_SEQI, CHILD(117), TILEPRO_OPC_SLTI, TILEPRO_OPC_SLTI_U, BITFIELD(18, 2) /* index 17 */, - TILE_OPC_ADD, TILE_OPC_S1A, TILE_OPC_S2A, TILE_OPC_SUB, + TILEPRO_OPC_ADD, TILEPRO_OPC_S1A, TILEPRO_OPC_S2A, TILEPRO_OPC_SUB, BITFIELD(18, 2) /* index 22 */, - TILE_OPC_MNZ, TILE_OPC_MVNZ, TILE_OPC_MVZ, TILE_OPC_MZ, + TILEPRO_OPC_MNZ, TILEPRO_OPC_MVNZ, TILEPRO_OPC_MVZ, TILEPRO_OPC_MZ, BITFIELD(18, 2) /* index 27 */, - TILE_OPC_AND, TILE_OPC_NOR, CHILD(32), TILE_OPC_XOR, + TILEPRO_OPC_AND, TILEPRO_OPC_NOR, CHILD(32), TILEPRO_OPC_XOR, BITFIELD(12, 2) /* index 32 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(37), + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(37), BITFIELD(14, 2) /* index 37 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(42), + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(42), BITFIELD(16, 2) /* index 42 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_MOVE, + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_MOVE, BITFIELD(18, 2) /* index 47 */, - TILE_OPC_RL, TILE_OPC_SHL, TILE_OPC_SHR, TILE_OPC_SRA, + TILEPRO_OPC_RL, TILEPRO_OPC_SHL, TILEPRO_OPC_SHR, TILEPRO_OPC_SRA, BITFIELD(18, 2) /* index 52 */, - TILE_OPC_SLTE, TILE_OPC_SLTE_U, TILE_OPC_SLT, TILE_OPC_SLT_U, + TILEPRO_OPC_SLTE, TILEPRO_OPC_SLTE_U, TILEPRO_OPC_SLT, TILEPRO_OPC_SLT_U, BITFIELD(18, 2) /* index 57 */, - TILE_OPC_MULHLSA_UU, TILE_OPC_S3A, TILE_OPC_SEQ, TILE_OPC_SNE, + TILEPRO_OPC_MULHLSA_UU, TILEPRO_OPC_S3A, TILEPRO_OPC_SEQ, TILEPRO_OPC_SNE, BITFIELD(18, 2) /* index 62 */, - TILE_OPC_MULHH_SS, TILE_OPC_MULHH_UU, TILE_OPC_MULLL_SS, TILE_OPC_MULLL_UU, + TILEPRO_OPC_MULHH_SS, TILEPRO_OPC_MULHH_UU, TILEPRO_OPC_MULLL_SS, + TILEPRO_OPC_MULLL_UU, BITFIELD(18, 2) /* index 67 */, - TILE_OPC_MULHHA_SS, TILE_OPC_MULHHA_UU, TILE_OPC_MULLLA_SS, - TILE_OPC_MULLLA_UU, + TILEPRO_OPC_MULHHA_SS, TILEPRO_OPC_MULHHA_UU, TILEPRO_OPC_MULLLA_SS, + TILEPRO_OPC_MULLLA_UU, BITFIELD(0, 2) /* index 72 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(77), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(77), BITFIELD(2, 2) /* index 77 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(82), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(82), BITFIELD(4, 2) /* index 82 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(87), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(87), BITFIELD(6, 2) /* index 87 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(92), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(92), BITFIELD(8, 2) /* index 92 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(97), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(97), BITFIELD(10, 2) /* index 97 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_INFO, + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_INFO, BITFIELD(6, 2) /* index 102 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(107), + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(107), BITFIELD(8, 2) /* index 107 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(112), + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(112), BITFIELD(10, 2) /* index 112 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_MOVEI, + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_MOVEI, BITFIELD(15, 5) /* index 117 */, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_RLI, - TILE_OPC_RLI, TILE_OPC_RLI, TILE_OPC_RLI, TILE_OPC_SHLI, TILE_OPC_SHLI, - TILE_OPC_SHLI, TILE_OPC_SHLI, TILE_OPC_SHRI, TILE_OPC_SHRI, TILE_OPC_SHRI, - TILE_OPC_SHRI, TILE_OPC_SRAI, TILE_OPC_SRAI, TILE_OPC_SRAI, TILE_OPC_SRAI, - CHILD(150), CHILD(159), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_RLI, TILEPRO_OPC_RLI, TILEPRO_OPC_RLI, TILEPRO_OPC_RLI, + TILEPRO_OPC_SHLI, TILEPRO_OPC_SHLI, TILEPRO_OPC_SHLI, TILEPRO_OPC_SHLI, + TILEPRO_OPC_SHRI, TILEPRO_OPC_SHRI, TILEPRO_OPC_SHRI, TILEPRO_OPC_SHRI, + TILEPRO_OPC_SRAI, TILEPRO_OPC_SRAI, TILEPRO_OPC_SRAI, TILEPRO_OPC_SRAI, + CHILD(150), CHILD(159), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(12, 3) /* index 150 */, - TILE_OPC_NONE, TILE_OPC_BITX, TILE_OPC_BYTEX, TILE_OPC_CLZ, TILE_OPC_CTZ, - TILE_OPC_FNOP, TILE_OPC_NOP, TILE_OPC_PCNT, + TILEPRO_OPC_NONE, TILEPRO_OPC_BITX, TILEPRO_OPC_BYTEX, TILEPRO_OPC_CLZ, + TILEPRO_OPC_CTZ, TILEPRO_OPC_FNOP, TILEPRO_OPC_NOP, TILEPRO_OPC_PCNT, BITFIELD(12, 3) /* index 159 */, - TILE_OPC_TBLIDXB0, TILE_OPC_TBLIDXB1, TILE_OPC_TBLIDXB2, TILE_OPC_TBLIDXB3, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_TBLIDXB0, TILEPRO_OPC_TBLIDXB1, TILEPRO_OPC_TBLIDXB2, + TILEPRO_OPC_TBLIDXB3, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, }; static const unsigned short decode_Y1_fsm[140] = { BITFIELD(59, 4) /* index 0 */, - TILE_OPC_NONE, CHILD(17), CHILD(22), CHILD(27), CHILD(47), CHILD(52), - CHILD(57), TILE_OPC_ADDI, CHILD(62), CHILD(92), TILE_OPC_SEQI, CHILD(107), - TILE_OPC_SLTI, TILE_OPC_SLTI_U, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NONE, CHILD(17), CHILD(22), CHILD(27), CHILD(47), CHILD(52), + CHILD(57), TILEPRO_OPC_ADDI, CHILD(62), CHILD(92), TILEPRO_OPC_SEQI, + CHILD(107), TILEPRO_OPC_SLTI, TILEPRO_OPC_SLTI_U, TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, BITFIELD(49, 2) /* index 17 */, - TILE_OPC_ADD, TILE_OPC_S1A, TILE_OPC_S2A, TILE_OPC_SUB, + TILEPRO_OPC_ADD, TILEPRO_OPC_S1A, TILEPRO_OPC_S2A, TILEPRO_OPC_SUB, BITFIELD(49, 2) /* index 22 */, - TILE_OPC_NONE, TILE_OPC_MNZ, TILE_OPC_MZ, TILE_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_MNZ, TILEPRO_OPC_MZ, TILEPRO_OPC_NONE, BITFIELD(49, 2) /* index 27 */, - TILE_OPC_AND, TILE_OPC_NOR, CHILD(32), TILE_OPC_XOR, + TILEPRO_OPC_AND, TILEPRO_OPC_NOR, CHILD(32), TILEPRO_OPC_XOR, BITFIELD(43, 2) /* index 32 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(37), + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(37), BITFIELD(45, 2) /* index 37 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(42), + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(42), BITFIELD(47, 2) /* index 42 */, - TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_MOVE, + TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_MOVE, BITFIELD(49, 2) /* index 47 */, - TILE_OPC_RL, TILE_OPC_SHL, TILE_OPC_SHR, TILE_OPC_SRA, + TILEPRO_OPC_RL, TILEPRO_OPC_SHL, TILEPRO_OPC_SHR, TILEPRO_OPC_SRA, BITFIELD(49, 2) /* index 52 */, - TILE_OPC_SLTE, TILE_OPC_SLTE_U, TILE_OPC_SLT, TILE_OPC_SLT_U, + TILEPRO_OPC_SLTE, TILEPRO_OPC_SLTE_U, TILEPRO_OPC_SLT, TILEPRO_OPC_SLT_U, BITFIELD(49, 2) /* index 57 */, - TILE_OPC_NONE, TILE_OPC_S3A, TILE_OPC_SEQ, TILE_OPC_SNE, + TILEPRO_OPC_NONE, TILEPRO_OPC_S3A, TILEPRO_OPC_SEQ, TILEPRO_OPC_SNE, BITFIELD(31, 2) /* index 62 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(67), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(67), BITFIELD(33, 2) /* index 67 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(72), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(72), BITFIELD(35, 2) /* index 72 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(77), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(77), BITFIELD(37, 2) /* index 77 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(82), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(82), BITFIELD(39, 2) /* index 82 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(87), + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(87), BITFIELD(41, 2) /* index 87 */, - TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_INFO, + TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_INFO, BITFIELD(37, 2) /* index 92 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(97), + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(97), BITFIELD(39, 2) /* index 97 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(102), + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(102), BITFIELD(41, 2) /* index 102 */, - TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_MOVEI, + TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_MOVEI, BITFIELD(48, 3) /* index 107 */, - TILE_OPC_NONE, TILE_OPC_RLI, TILE_OPC_SHLI, TILE_OPC_SHRI, TILE_OPC_SRAI, - CHILD(116), TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_RLI, TILEPRO_OPC_SHLI, TILEPRO_OPC_SHRI, + TILEPRO_OPC_SRAI, CHILD(116), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(43, 3) /* index 116 */, - TILE_OPC_NONE, CHILD(125), CHILD(130), CHILD(135), TILE_OPC_NONE, - TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NONE, CHILD(125), CHILD(130), CHILD(135), TILEPRO_OPC_NONE, + TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(46, 2) /* index 125 */, - TILE_OPC_FNOP, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_FNOP, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(46, 2) /* index 130 */, - TILE_OPC_ILL, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_ILL, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, BITFIELD(46, 2) /* index 135 */, - TILE_OPC_NOP, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, + TILEPRO_OPC_NOP, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, }; static const unsigned short decode_Y2_fsm[24] = { BITFIELD(56, 3) /* index 0 */, - CHILD(9), TILE_OPC_LB_U, TILE_OPC_LH, TILE_OPC_LH_U, TILE_OPC_LW, - TILE_OPC_SB, TILE_OPC_SH, TILE_OPC_SW, + CHILD(9), TILEPRO_OPC_LB_U, TILEPRO_OPC_LH, TILEPRO_OPC_LH_U, + TILEPRO_OPC_LW, TILEPRO_OPC_SB, TILEPRO_OPC_SH, TILEPRO_OPC_SW, BITFIELD(20, 2) /* index 9 */, - TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, CHILD(14), + TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, CHILD(14), BITFIELD(22, 2) /* index 14 */, - TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, CHILD(19), + TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, CHILD(19), BITFIELD(24, 2) /* index 19 */, - TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_PREFETCH, + TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_PREFETCH, }; #undef BITFIELD #undef CHILD const unsigned short * const -tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS] = +tilepro_bundle_decoder_fsms[TILEPRO_NUM_PIPELINE_ENCODINGS] = { decode_X0_fsm, decode_X1_fsm, @@ -2191,220 +2297,220 @@ tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS] = decode_Y1_fsm, decode_Y2_fsm }; -const struct tile_operand tile_operands[43] = +const struct tilepro_operand tilepro_operands[43] = { { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_IMM8_X0), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM8_X0), 8, 1, 0, 0, 0, 0, create_Imm8_X0, get_Imm8_X0 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_IMM8_X1), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM8_X1), 8, 1, 0, 0, 0, 0, create_Imm8_X1, get_Imm8_X1 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_IMM8_Y0), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM8_Y0), 8, 1, 0, 0, 0, 0, create_Imm8_Y0, get_Imm8_Y0 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_IMM8_Y1), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM8_Y1), 8, 1, 0, 0, 0, 0, create_Imm8_Y1, get_Imm8_Y1 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_IMM16_X0), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM16_X0), 16, 1, 0, 0, 0, 0, create_Imm16_X0, get_Imm16_X0 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_IMM16_X1), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM16_X1), 16, 1, 0, 0, 0, 0, create_Imm16_X1, get_Imm16_X1 }, { - TILE_OP_TYPE_ADDRESS, BFD_RELOC(TILE_JOFFLONG_X1), - 29, 1, 0, 0, 1, TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, + TILEPRO_OP_TYPE_ADDRESS, BFD_RELOC(TILEPRO_JOFFLONG_X1), + 29, 1, 0, 0, 1, TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, create_JOffLong_X1, get_JOffLong_X1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 0, 1, 0, 0, create_Dest_X0, get_Dest_X0 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcA_X0, get_SrcA_X0 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 0, 1, 0, 0, create_Dest_X1, get_Dest_X1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcA_X1, get_SrcA_X1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 0, 1, 0, 0, create_Dest_Y0, get_Dest_Y0 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcA_Y0, get_SrcA_Y0 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 0, 1, 0, 0, create_Dest_Y1, get_Dest_Y1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcA_Y1, get_SrcA_Y1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcA_Y2, get_SrcA_Y2 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcB_X0, get_SrcB_X0 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcB_X1, get_SrcB_X1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcB_Y0, get_SrcB_Y0 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcB_Y1, get_SrcB_Y1 }, { - TILE_OP_TYPE_ADDRESS, BFD_RELOC(TILE_BROFF_X1), - 17, 1, 0, 0, 1, TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, + TILEPRO_OP_TYPE_ADDRESS, BFD_RELOC(TILEPRO_BROFF_X1), + 17, 1, 0, 0, 1, TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, create_BrOff_X1, get_BrOff_X1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 1, 0, 0, create_Dest_X0, get_Dest_X0 }, { - TILE_OP_TYPE_ADDRESS, BFD_RELOC(NONE), - 28, 1, 0, 0, 1, TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, + TILEPRO_OP_TYPE_ADDRESS, BFD_RELOC(NONE), + 28, 1, 0, 0, 1, TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, create_JOff_X1, get_JOff_X1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 0, 1, 0, 0, create_SrcBDest_Y2, get_SrcBDest_Y2 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 1, 0, 0, create_SrcA_X1, get_SrcA_X1 }, { - TILE_OP_TYPE_SPR, BFD_RELOC(TILE_MF_IMM15_X1), + TILEPRO_OP_TYPE_SPR, BFD_RELOC(TILEPRO_MF_IMM15_X1), 15, 0, 0, 0, 0, 0, create_MF_Imm15_X1, get_MF_Imm15_X1 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_MMSTART_X0), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_MMSTART_X0), 5, 0, 0, 0, 0, 0, create_MMStart_X0, get_MMStart_X0 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_MMEND_X0), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_MMEND_X0), 5, 0, 0, 0, 0, 0, create_MMEnd_X0, get_MMEnd_X0 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_MMSTART_X1), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_MMSTART_X1), 5, 0, 0, 0, 0, 0, create_MMStart_X1, get_MMStart_X1 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_MMEND_X1), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_MMEND_X1), 5, 0, 0, 0, 0, 0, create_MMEnd_X1, get_MMEnd_X1 }, { - TILE_OP_TYPE_SPR, BFD_RELOC(TILE_MT_IMM15_X1), + TILEPRO_OP_TYPE_SPR, BFD_RELOC(TILEPRO_MT_IMM15_X1), 15, 0, 0, 0, 0, 0, create_MT_Imm15_X1, get_MT_Imm15_X1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 1, 0, 0, create_Dest_Y0, get_Dest_Y0 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_SHAMT_X0), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_SHAMT_X0), 5, 0, 0, 0, 0, 0, create_ShAmt_X0, get_ShAmt_X0 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_SHAMT_X1), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_SHAMT_X1), 5, 0, 0, 0, 0, 0, create_ShAmt_X1, get_ShAmt_X1 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_SHAMT_Y0), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_SHAMT_Y0), 5, 0, 0, 0, 0, 0, create_ShAmt_Y0, get_ShAmt_Y0 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_SHAMT_Y1), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_SHAMT_Y1), 5, 0, 0, 0, 0, 0, create_ShAmt_Y1, get_ShAmt_Y1 }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 6, 0, 1, 0, 0, 0, create_SrcBDest_Y2, get_SrcBDest_Y2 }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_DEST_IMM8_X1), 8, 1, 0, 0, 0, 0, create_Dest_Imm8_X1, get_Dest_Imm8_X1 }, { - TILE_OP_TYPE_ADDRESS, BFD_RELOC(TILE_SN_BROFF), - 10, 1, 0, 0, 1, TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES, + TILEPRO_OP_TYPE_ADDRESS, BFD_RELOC(NONE), + 10, 1, 0, 0, 1, TILEPRO_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES, create_BrOff_SN, get_BrOff_SN }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_SN_UIMM8), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE), 8, 0, 0, 0, 0, 0, create_Imm8_SN, get_Imm8_SN }, { - TILE_OP_TYPE_IMMEDIATE, BFD_RELOC(TILE_SN_IMM8), + TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE), 8, 1, 0, 0, 0, 0, create_Imm8_SN, get_Imm8_SN }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 2, 0, 0, 1, 0, 0, create_Dest_SN, get_Dest_SN }, { - TILE_OP_TYPE_REGISTER, BFD_RELOC(NONE), + TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), 2, 0, 1, 0, 0, 0, create_Src_SN, get_Src_SN } @@ -2416,10 +2522,10 @@ const struct tile_operand tile_operands[43] = /* Given a set of bundle bits and a specific pipe, returns which * instruction the bundle contains in that pipe. */ -const struct tile_opcode * -find_opcode(tile_bundle_bits bits, tile_pipeline pipe) +const struct tilepro_opcode * +find_opcode(tilepro_bundle_bits bits, tilepro_pipeline pipe) { - const unsigned short *table = tile_bundle_decoder_fsms[pipe]; + const unsigned short *table = tilepro_bundle_decoder_fsms[pipe]; int index = 0; while (1) @@ -2429,51 +2535,51 @@ find_opcode(tile_bundle_bits bits, tile_pipeline pipe) ((unsigned int)(bits >> (bitspec & 63))) & (bitspec >> 6); unsigned short next = table[index + 1 + bitfield]; - if (next <= TILE_OPC_NONE) - return &tile_opcodes[next]; + if (next <= TILEPRO_OPC_NONE) + return &tilepro_opcodes[next]; - index = next - TILE_OPC_NONE; + index = next - TILEPRO_OPC_NONE; } } int -parse_insn_tile(tile_bundle_bits bits, - unsigned int pc, - struct tile_decoded_instruction - decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]) +parse_insn_tilepro(tilepro_bundle_bits bits, + unsigned int pc, + struct tilepro_decoded_instruction + decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE]) { int num_instructions = 0; int pipe; int min_pipe, max_pipe; - if ((bits & TILE_BUNDLE_Y_ENCODING_MASK) == 0) + if ((bits & TILEPRO_BUNDLE_Y_ENCODING_MASK) == 0) { - min_pipe = TILE_PIPELINE_X0; - max_pipe = TILE_PIPELINE_X1; + min_pipe = TILEPRO_PIPELINE_X0; + max_pipe = TILEPRO_PIPELINE_X1; } else { - min_pipe = TILE_PIPELINE_Y0; - max_pipe = TILE_PIPELINE_Y2; + min_pipe = TILEPRO_PIPELINE_Y0; + max_pipe = TILEPRO_PIPELINE_Y2; } /* For each pipe, find an instruction that fits. */ for (pipe = min_pipe; pipe <= max_pipe; pipe++) { - const struct tile_opcode *opc; - struct tile_decoded_instruction *d; + const struct tilepro_opcode *opc; + struct tilepro_decoded_instruction *d; int i; d = &decoded[num_instructions++]; - opc = find_opcode (bits, (tile_pipeline)pipe); + opc = find_opcode (bits, (tilepro_pipeline)pipe); d->opcode = opc; /* Decode each operand, sign extending, etc. as appropriate. */ for (i = 0; i < opc->num_operands; i++) { - const struct tile_operand *op = - &tile_operands[opc->operands[pipe][i]]; + const struct tilepro_operand *op = + &tilepro_operands[opc->operands[pipe][i]]; int opval = op->extract (bits); if (op->is_signed) { @@ -2483,9 +2589,9 @@ parse_insn_tile(tile_bundle_bits bits, } /* Adjust PC-relative scaled branch offsets. */ - if (op->type == TILE_OP_TYPE_ADDRESS) + if (op->type == TILEPRO_OP_TYPE_ADDRESS) { - opval *= TILE_BUNDLE_SIZE_IN_BYTES; + opval *= TILEPRO_BUNDLE_SIZE_IN_BYTES; opval += (int)pc; } diff --git a/arch/tile/kernel/tile-desc_64.c b/arch/tile/kernel/tile-desc_64.c index d57007bed77f..65b5f8aca706 100644 --- a/arch/tile/kernel/tile-desc_64.c +++ b/arch/tile/kernel/tile-desc_64.c @@ -1,3 +1,23 @@ +/* TILE-Gx opcode information. + * + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * + * + * + * + */ + /* This define is BFD_RELOC_##x for real bfd, or -1 for everyone else. */ #define BFD_RELOC(x) -1 @@ -6,10 +26,8 @@ #define TREG_SN 56 #define TREG_ZERO 63 -/* FIXME: Rename this. */ -#include - #include +#include const struct tilegx_opcode tilegx_opcodes[334] = { @@ -2040,12 +2058,12 @@ const struct tilegx_operand tilegx_operands[35] = create_BrOff_X1, get_BrOff_X1 }, { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE), + TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_MMSTART_X0), 6, 0, 0, 0, 0, 0, create_BFStart_X0, get_BFStart_X0 }, { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE), + TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_MMEND_X0), 6, 0, 0, 0, 0, 0, create_BFEnd_X0, get_BFEnd_X0 }, diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index f9803dfa7357..4f47b8a356df 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c @@ -19,13 +19,12 @@ #include #include #include -#include -#include #include #include #include #include +#include void __init trap_init(void) { @@ -135,7 +134,7 @@ static int special_ill(bundle_bits bundle, int *sigp, int *codep) if (get_UnaryOpcodeExtension_X1(bundle) != ILL_UNARY_OPCODE_X1) return 0; #else - if (bundle & TILE_BUNDLE_Y_ENCODING_MASK) + if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) return 0; if (get_Opcode_X1(bundle) != SHUN_0_OPCODE_X1) return 0; From e4221314a593b00e035f70efbef52021f9a3a5fc Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 3 Nov 2011 17:48:25 -0700 Subject: [PATCH 1386/1596] IB/mthca: Fix buddy->num_free allocation size The num_free field of mthca_buddy has a type of array of unsigned int while it was allocated as an array of pointers. On 64-bit platforms this allocates twice more than required. Fix this by allocating the correct size for the type. This is the same bug just fixed in mlx4 by Eli Cohen . Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index ab876f928a1b..ed9a989e501b 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -146,7 +146,7 @@ static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order) buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *), GFP_KERNEL); - buddy->num_free = kzalloc((buddy->max_order + 1) * sizeof (int *), + buddy->num_free = kcalloc((buddy->max_order + 1), sizeof *buddy->num_free, GFP_KERNEL); if (!buddy->bits || !buddy->num_free) goto err_out; From 50e07f888cb24b55e0d8283f631907794dd757c2 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 25 Oct 2011 14:01:26 +0200 Subject: [PATCH 1387/1596] dt: add empty of_machine_is_compatible The patch adds an empty function for non-dt build, so that drivers migrating to dt can save some '#ifdef CONFIG_OF'. v3: New patch Signed-off-by: Stephen Warren Signed-off-by: Grant Likely --- include/linux/of.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/of.h b/include/linux/of.h index 4386c5fee57c..0e89aa0bf07a 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -326,6 +326,11 @@ static inline int of_alias_get_id(struct device_node *np, const char *stem) return -ENOSYS; } +static inline int of_machine_is_compatible(const char *compat) +{ + return 0; +} + #define of_match_ptr(_ptr) NULL #define of_match_node(_matches, _node) NULL #endif /* CONFIG_OF */ From 161ebf9fcca967e7396bb076af5ed18539497a3f Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Sat, 29 Oct 2011 17:17:58 +0400 Subject: [PATCH 1388/1596] CIFS: Simplify setlk error handling for mandatory locking Now we allocate a lock structure at first, then we request to the server and save the lock if server returned OK though void function - it prevents the situation when we locked a file on the server and then return -ENOMEM from setlk. Signed-off-by: Pavel Shilovsky Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/file.c | 64 +++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c1f063cd1b0c..d9cc07fec99f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -672,7 +672,7 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock) } static bool -cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset, +__cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, __u8 type, __u16 netfid, struct cifsLockInfo **conf_lock) { @@ -694,6 +694,14 @@ cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset, return false; } +static bool +cifs_find_lock_conflict(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock, + struct cifsLockInfo **conf_lock) +{ + return __cifs_find_lock_conflict(cinode, lock->offset, lock->length, + lock->type, lock->netfid, conf_lock); +} + static int cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, __u8 type, __u16 netfid, struct file_lock *flock) @@ -704,8 +712,8 @@ cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, mutex_lock(&cinode->lock_mutex); - exist = cifs_find_lock_conflict(cinode, offset, length, type, netfid, - &conf_lock); + exist = __cifs_find_lock_conflict(cinode, offset, length, type, netfid, + &conf_lock); if (exist) { flock->fl_start = conf_lock->offset; flock->fl_end = conf_lock->offset + conf_lock->length - 1; @@ -723,40 +731,27 @@ cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, return rc; } -static int -cifs_lock_add(struct cifsInodeInfo *cinode, __u64 len, __u64 offset, - __u8 type, __u16 netfid) +static void +cifs_lock_add(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock) { - struct cifsLockInfo *li; - - li = cifs_lock_init(len, offset, type, netfid); - if (!li) - return -ENOMEM; - mutex_lock(&cinode->lock_mutex); - list_add_tail(&li->llist, &cinode->llist); + list_add_tail(&lock->llist, &cinode->llist); mutex_unlock(&cinode->lock_mutex); - return 0; } static int -cifs_lock_add_if(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, - __u8 type, __u16 netfid, bool wait) +cifs_lock_add_if(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock, + bool wait) { - struct cifsLockInfo *lock, *conf_lock; + struct cifsLockInfo *conf_lock; bool exist; int rc = 0; - lock = cifs_lock_init(length, offset, type, netfid); - if (!lock) - return -ENOMEM; - try_again: exist = false; mutex_lock(&cinode->lock_mutex); - exist = cifs_find_lock_conflict(cinode, offset, length, type, netfid, - &conf_lock); + exist = cifs_find_lock_conflict(cinode, lock, &conf_lock); if (!exist && cinode->can_cache_brlcks) { list_add_tail(&lock->llist, &cinode->llist); mutex_unlock(&cinode->lock_mutex); @@ -781,7 +776,6 @@ cifs_lock_add_if(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, } } - kfree(lock); mutex_unlock(&cinode->lock_mutex); return rc; } @@ -1254,20 +1248,26 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, } if (lock) { - rc = cifs_lock_add_if(cinode, flock->fl_start, length, - type, netfid, wait_flag); + struct cifsLockInfo *lock; + + lock = cifs_lock_init(length, flock->fl_start, type, netfid); + if (!lock) + return -ENOMEM; + + rc = cifs_lock_add_if(cinode, lock, wait_flag); if (rc < 0) - return rc; - else if (!rc) + kfree(lock); + if (rc <= 0) goto out; rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, flock->fl_start, 0, 1, type, wait_flag, 0); - if (rc == 0) { - /* For Windows locks we must store them. */ - rc = cifs_lock_add(cinode, length, flock->fl_start, - type, netfid); + if (rc) { + kfree(lock); + goto out; } + + cifs_lock_add(cinode, lock); } else if (unlock) rc = cifs_unlock_range(cfile, flock, xid); From a88b470773bc5b640292d8be7b8e7e1011a86639 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Sat, 29 Oct 2011 17:17:59 +0400 Subject: [PATCH 1389/1596] CIFS: Cleanup byte-range locking code style Reorder parms of cifs_lock_init, trivially simplify getlk code and remove extra {} in cifs_lock_add_if. Cc: Dan Carpenter Acked-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/file.c | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d9cc07fec99f..cf0b1539b321 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -645,20 +645,20 @@ int cifs_closedir(struct inode *inode, struct file *file) } static struct cifsLockInfo * -cifs_lock_init(__u64 len, __u64 offset, __u8 type, __u16 netfid) +cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 netfid) { - struct cifsLockInfo *li = + struct cifsLockInfo *lock = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); - if (!li) - return li; - li->netfid = netfid; - li->offset = offset; - li->length = len; - li->type = type; - li->pid = current->tgid; - INIT_LIST_HEAD(&li->blist); - init_waitqueue_head(&li->block_q); - return li; + if (!lock) + return lock; + lock->offset = offset; + lock->length = length; + lock->type = type; + lock->netfid = netfid; + lock->pid = current->tgid; + INIT_LIST_HEAD(&lock->blist); + init_waitqueue_head(&lock->block_q); + return lock; } static void @@ -770,10 +770,8 @@ cifs_lock_add_if(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock, (lock->blist.next == &lock->blist)); if (!rc) goto try_again; - else { - mutex_lock(&cinode->lock_mutex); - list_del_init(&lock->blist); - } + mutex_lock(&cinode->lock_mutex); + list_del_init(&lock->blist); } mutex_unlock(&cinode->lock_mutex); @@ -927,7 +925,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) else type = CIFS_WRLCK; - lck = cifs_lock_init(length, flock->fl_start, type, + lck = cifs_lock_init(flock->fl_start, length, type, cfile->netfid); if (!lck) { rc = -ENOMEM; @@ -1064,14 +1062,12 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, if (rc != 0) cERROR(1, "Error unlocking previously locked " "range %d during test of lock", rc); - rc = 0; - return rc; + return 0; } if (type & LOCKING_ANDX_SHARED_LOCK) { flock->fl_type = F_WRLCK; - rc = 0; - return rc; + return 0; } rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, @@ -1089,8 +1085,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, } else flock->fl_type = F_WRLCK; - rc = 0; - return rc; + return 0; } static void @@ -1250,7 +1245,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, if (lock) { struct cifsLockInfo *lock; - lock = cifs_lock_init(length, flock->fl_start, type, netfid); + lock = cifs_lock_init(flock->fl_start, length, type, netfid); if (!lock) return -ENOMEM; From a17f091d1a7c570804cfc2c77701634da88f8ecf Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 2 Nov 2011 21:52:08 -0700 Subject: [PATCH 1390/1596] target: Add generic active I/O shutdown logic This patch adds the initial pieces of generic active I/O shutdown logic. This is intended to be a 'opt-in' feature for fabric modules that includes the following functions to provide a mechinism for fabric modules to track se_cmd via se_session->sess_cmd_list: *) target_get_sess_cmd() - Add se_cmd to sess->sess_cmd_list, called from fabric module incoming I/O path. *) target_put_sess_cmd() - Check for completion or drop se_cmd from ->sess_cmd_list *) target_splice_sess_cmd_list() - Splice active I/O list from ->sess_cmd_list to ->sess_wait_list, can called with HW fabric lock held. *) target_wait_for_sess_cmds() - Walk ->sess_wait_list waiting on individual ->cmd_wait_comp. Optional transport_wait_for_tasks() call. target_splice_sess_cmd_list() is allowed to be called under HW fabric lock, and performs the splice into se_sess->sess_wait_list and set se_cmd->cmd_wait_set. Then target_wait_for_sess_cmds() walks the list waiting for individual target_put_sess_cmd() fabric callbacks to complete. It also adds TFO->check_release_cmd() to split the completion and memory release calls, where a fabric module uses target_put_sess_cmd() to check for I/O completion during session shutdown. This is currently pushed out into fabric modules as current fabric code may sleep here waiting for TFO->check_stop_free() to complete in main response path, and because target_wait_for_sess_cmds() calling TFO->release_cmd() to free fabric descriptor memory directly. Cc: Christoph Hellwig Cc: Roland Dreier Signed-off-by: Nicholas A. Bellinger --- drivers/target/target_core_transport.c | 132 +++++++++++++++++++++++- include/target/target_core_base.h | 9 ++ include/target/target_core_fabric_ops.h | 4 + include/target/target_core_transport.h | 6 +- 4 files changed, 145 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 81bc355be317..e84b26ffb17b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -268,6 +268,9 @@ struct se_session *transport_init_session(void) } INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); + INIT_LIST_HEAD(&se_sess->sess_cmd_list); + INIT_LIST_HEAD(&se_sess->sess_wait_list); + spin_lock_init(&se_sess->sess_cmd_lock); return se_sess; } @@ -1505,11 +1508,12 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_ordered_node); INIT_LIST_HEAD(&cmd->se_qf_node); INIT_LIST_HEAD(&cmd->se_queue_node); - + INIT_LIST_HEAD(&cmd->se_cmd_list); INIT_LIST_HEAD(&cmd->t_task_list); init_completion(&cmd->transport_lun_fe_stop_comp); init_completion(&cmd->transport_lun_stop_comp); init_completion(&cmd->t_transport_stop_comp); + init_completion(&cmd->cmd_wait_comp); spin_lock_init(&cmd->t_state_lock); atomic_set(&cmd->transport_dev_active, 1); @@ -3950,6 +3954,14 @@ void transport_release_cmd(struct se_cmd *cmd) core_tmr_release_req(cmd->se_tmr_req); if (cmd->t_task_cdb != cmd->__t_task_cdb) kfree(cmd->t_task_cdb); + /* + * Check if target_wait_for_sess_cmds() is expecting to + * release se_cmd directly here.. + */ + if (cmd->check_release != 0 && cmd->se_tfo->check_release_cmd) + if (cmd->se_tfo->check_release_cmd(cmd) != 0) + return; + cmd->se_tfo->release_cmd(cmd); } EXPORT_SYMBOL(transport_release_cmd); @@ -3977,6 +3989,114 @@ void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) } EXPORT_SYMBOL(transport_generic_free_cmd); +/* target_get_sess_cmd - Add command to active ->sess_cmd_list + * @se_sess: session to reference + * @se_cmd: command descriptor to add + */ +void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); + se_cmd->check_release = 1; + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); +} +EXPORT_SYMBOL(target_get_sess_cmd); + +/* target_put_sess_cmd - Check for active I/O shutdown or list delete + * @se_sess: session to reference + * @se_cmd: command descriptor to drop + */ +int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + if (list_empty(&se_cmd->se_cmd_list)) { + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + WARN_ON(1); + return 0; + } + + if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + complete(&se_cmd->cmd_wait_comp); + return 1; + } + list_del(&se_cmd->se_cmd_list); + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + + return 0; +} +EXPORT_SYMBOL(target_put_sess_cmd); + +/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list + * @se_sess: session to split + */ +void target_splice_sess_cmd_list(struct se_session *se_sess) +{ + struct se_cmd *se_cmd; + unsigned long flags; + + WARN_ON(!list_empty(&se_sess->sess_wait_list)); + INIT_LIST_HEAD(&se_sess->sess_wait_list); + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + se_sess->sess_tearing_down = 1; + + list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); + + list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) + se_cmd->cmd_wait_set = 1; + + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); +} +EXPORT_SYMBOL(target_splice_sess_cmd_list); + +/* target_wait_for_sess_cmds - Wait for outstanding descriptors + * @se_sess: session to wait for active I/O + * @wait_for_tasks: Make extra transport_wait_for_tasks call + */ +void target_wait_for_sess_cmds( + struct se_session *se_sess, + int wait_for_tasks) +{ + struct se_cmd *se_cmd, *tmp_cmd; + bool rc = false; + + list_for_each_entry_safe(se_cmd, tmp_cmd, + &se_sess->sess_wait_list, se_cmd_list) { + list_del(&se_cmd->se_cmd_list); + + pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" + " %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + + if (wait_for_tasks) { + pr_debug("Calling transport_wait_for_tasks se_cmd: %p t_state: %d," + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + + rc = transport_wait_for_tasks(se_cmd); + + pr_debug("After transport_wait_for_tasks se_cmd: %p t_state: %d," + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + } + + if (!rc) { + wait_for_completion(&se_cmd->cmd_wait_comp); + pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); + } + + se_cmd->se_tfo->release_cmd(se_cmd); + } +} +EXPORT_SYMBOL(target_wait_for_sess_cmds); + /* transport_lun_wait_for_tasks(): * * Called from ConfigFS context to stop the passed struct se_cmd to allow @@ -4153,14 +4273,14 @@ int transport_clear_lun_from_sessions(struct se_lun *lun) * Called from frontend fabric context to wait for storage engine * to pause and/or release frontend generated struct se_cmd. */ -void transport_wait_for_tasks(struct se_cmd *cmd) +bool transport_wait_for_tasks(struct se_cmd *cmd) { unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; + return false; } /* * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE @@ -4168,7 +4288,7 @@ void transport_wait_for_tasks(struct se_cmd *cmd) */ if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; + return false; } /* * If we are already stopped due to an external event (ie: LUN shutdown) @@ -4211,7 +4331,7 @@ void transport_wait_for_tasks(struct se_cmd *cmd) if (!atomic_read(&cmd->t_transport_active) || atomic_read(&cmd->t_transport_aborted)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; + return false; } atomic_set(&cmd->t_transport_stop, 1); @@ -4236,6 +4356,8 @@ void transport_wait_for_tasks(struct se_cmd *cmd) cmd->se_tfo->get_task_tag(cmd)); spin_unlock_irqrestore(&cmd->t_state_lock, flags); + + return true; } EXPORT_SYMBOL(transport_wait_for_tasks); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index d571bcfd16ad..dd245b68be5a 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -425,6 +425,9 @@ struct se_cmd { enum transport_state_table t_state; /* Transport specific error status */ int transport_error_status; + /* Used to signal cmd->se_tfo->check_release_cmd() usage per cmd */ + int check_release:1; + int cmd_wait_set:1; /* See se_cmd_flags_table */ u32 se_cmd_flags; u32 se_ordered_id; @@ -451,6 +454,8 @@ struct se_cmd { struct se_session *se_sess; struct se_tmr_req *se_tmr_req; struct list_head se_queue_node; + struct list_head se_cmd_list; + struct completion cmd_wait_comp; struct target_core_fabric_ops *se_tfo; int (*transport_emulate_cdb)(struct se_cmd *); void (*transport_complete_callback)(struct se_cmd *); @@ -558,12 +563,16 @@ struct se_node_acl { } ____cacheline_aligned; struct se_session { + int sess_tearing_down:1; u64 sess_bin_isid; struct se_node_acl *se_node_acl; struct se_portal_group *se_tpg; void *fabric_sess_ptr; struct list_head sess_list; struct list_head sess_acl_list; + struct list_head sess_cmd_list; + struct list_head sess_wait_list; + spinlock_t sess_cmd_lock; } ____cacheline_aligned; struct se_device; diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric_ops.h index 04c591da0844..0256825f923d 100644 --- a/include/target/target_core_fabric_ops.h +++ b/include/target/target_core_fabric_ops.h @@ -52,6 +52,10 @@ struct target_core_fabric_ops { * Returning 0 will signal a descriptor has not been released. */ int (*check_stop_free)(struct se_cmd *); + /* + * Optional check for active I/O shutdown + */ + int (*check_release_cmd)(struct se_cmd *); void (*release_cmd)(struct se_cmd *); /* * Called with spin_lock_bh(struct se_portal_group->session_lock held. diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h index d1b68c9ccb75..c16e9431dd01 100644 --- a/include/target/target_core_transport.h +++ b/include/target/target_core_transport.h @@ -164,12 +164,16 @@ extern bool target_stop_task(struct se_task *task, unsigned long *flags); extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, struct scatterlist *, u32); extern int transport_clear_lun_from_sessions(struct se_lun *); -extern void transport_wait_for_tasks(struct se_cmd *); +extern bool transport_wait_for_tasks(struct se_cmd *); extern int transport_check_aborted_status(struct se_cmd *, int); extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); extern void transport_send_task_abort(struct se_cmd *); extern void transport_release_cmd(struct se_cmd *); extern void transport_generic_free_cmd(struct se_cmd *, int); +extern void target_get_sess_cmd(struct se_session *, struct se_cmd *); +extern int target_put_sess_cmd(struct se_session *, struct se_cmd *); +extern void target_splice_sess_cmd_list(struct se_session *); +extern void target_wait_for_sess_cmds(struct se_session *, int); extern void transport_generic_wait_for_cmds(struct se_cmd *, int); extern void transport_do_task_sg_chain(struct se_cmd *); extern void transport_generic_process_write(struct se_cmd *); From eacac00ce5bfde8086cd0615fb53c986f7f970fe Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 3 Nov 2011 17:50:40 -0400 Subject: [PATCH 1391/1596] target: split core_scsi2_emulate_crh Split core_scsi2_emulate_crh into one routine each for the reserve and release side. The common code now is in a helper called by both routines. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_pr.c | 189 ++++++++++++------------- drivers/target/target_core_pr.h | 3 +- drivers/target/target_core_transport.c | 16 +-- 3 files changed, 102 insertions(+), 106 deletions(-) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 0c4f783f924c..830953a743d6 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -116,14 +116,99 @@ static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) return ret; } -static int core_scsi2_reservation_release(struct se_cmd *cmd) +static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, + struct se_node_acl *, struct se_session *); +static void core_scsi3_put_pr_reg(struct t10_pr_registration *); + +static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret) +{ + struct se_session *se_sess = cmd->se_sess; + struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + struct t10_pr_registration *pr_reg; + struct t10_reservation *pr_tmpl = &su_dev->t10_pr; + int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); + int conflict = 0; + + if (!crh) + return false; + + pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, + se_sess); + if (pr_reg) { + /* + * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE + * behavior + * + * A RESERVE(6) or RESERVE(10) command shall complete with GOOD + * status, but no reservation shall be established and the + * persistent reservation shall not be changed, if the command + * is received from a) and b) below. + * + * A RELEASE(6) or RELEASE(10) command shall complete with GOOD + * status, but the persistent reservation shall not be released, + * if the command is received from a) and b) + * + * a) An I_T nexus that is a persistent reservation holder; or + * b) An I_T nexus that is registered if a registrants only or + * all registrants type persistent reservation is present. + * + * In all other cases, a RESERVE(6) command, RESERVE(10) command, + * RELEASE(6) command, or RELEASE(10) command shall be processed + * as defined in SPC-2. + */ + if (pr_reg->pr_res_holder) { + core_scsi3_put_pr_reg(pr_reg); + *ret = 0; + return false; + } + if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || + (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || + (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || + (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { + core_scsi3_put_pr_reg(pr_reg); + *ret = 0; + return true; + } + core_scsi3_put_pr_reg(pr_reg); + conflict = 1; + } else { + /* + * Following spc2r20 5.5.1 Reservations overview: + * + * If a logical unit has executed a PERSISTENT RESERVE OUT + * command with the REGISTER or the REGISTER AND IGNORE + * EXISTING KEY service action and is still registered by any + * initiator, all RESERVE commands and all RELEASE commands + * regardless of initiator shall conflict and shall terminate + * with a RESERVATION CONFLICT status. + */ + spin_lock(&pr_tmpl->registration_lock); + conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1; + spin_unlock(&pr_tmpl->registration_lock); + } + + if (conflict) { + pr_err("Received legacy SPC-2 RESERVE/RELEASE" + " while active SPC-3 registrations exist," + " returning RESERVATION_CONFLICT\n"); + *ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + return true; + } + + return false; +} + +int target_scsi2_reservation_release(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg = sess->se_tpg; + int ret; if (!sess || !tpg) return 0; + if (target_check_scsi2_reservation_conflict(cmd, &ret)) + return ret; spin_lock(&dev->dev_reservation_lock); if (!dev->dev_reserved_node_acl || !sess) { @@ -150,11 +235,12 @@ static int core_scsi2_reservation_release(struct se_cmd *cmd) return 0; } -static int core_scsi2_reservation_reserve(struct se_cmd *cmd) +int target_scsi2_reservation_reserve(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg = sess->se_tpg; + int ret; if ((cmd->t_task_cdb[1] & 0x01) && (cmd->t_task_cdb[1] & 0x02)) { @@ -168,6 +254,8 @@ static int core_scsi2_reservation_reserve(struct se_cmd *cmd) */ if (!sess || !tpg) return 0; + if (target_check_scsi2_reservation_conflict(cmd, &ret)) + return ret; spin_lock(&dev->dev_reservation_lock); if (dev->dev_reserved_node_acl && @@ -200,99 +288,6 @@ static int core_scsi2_reservation_reserve(struct se_cmd *cmd) return 0; } -static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, - struct se_node_acl *, struct se_session *); -static void core_scsi3_put_pr_reg(struct t10_pr_registration *); - -/* - * Setup in target_core_transport.c:transport_generic_cmd_sequencer() - * and called via struct se_cmd->transport_emulate_cdb() in TCM processing - * thread context. - */ -int core_scsi2_emulate_crh(struct se_cmd *cmd) -{ - struct se_session *se_sess = cmd->se_sess; - struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; - struct t10_pr_registration *pr_reg; - struct t10_reservation *pr_tmpl = &su_dev->t10_pr; - unsigned char *cdb = &cmd->t_task_cdb[0]; - int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); - int conflict = 0; - - if (!se_sess) - return 0; - - if (!crh) - goto after_crh; - - pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, - se_sess); - if (pr_reg) { - /* - * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE - * behavior - * - * A RESERVE(6) or RESERVE(10) command shall complete with GOOD - * status, but no reservation shall be established and the - * persistent reservation shall not be changed, if the command - * is received from a) and b) below. - * - * A RELEASE(6) or RELEASE(10) command shall complete with GOOD - * status, but the persistent reservation shall not be released, - * if the command is received from a) and b) - * - * a) An I_T nexus that is a persistent reservation holder; or - * b) An I_T nexus that is registered if a registrants only or - * all registrants type persistent reservation is present. - * - * In all other cases, a RESERVE(6) command, RESERVE(10) command, - * RELEASE(6) command, or RELEASE(10) command shall be processed - * as defined in SPC-2. - */ - if (pr_reg->pr_res_holder) { - core_scsi3_put_pr_reg(pr_reg); - return 0; - } - if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || - (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || - (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || - (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { - core_scsi3_put_pr_reg(pr_reg); - return 0; - } - core_scsi3_put_pr_reg(pr_reg); - conflict = 1; - } else { - /* - * Following spc2r20 5.5.1 Reservations overview: - * - * If a logical unit has executed a PERSISTENT RESERVE OUT - * command with the REGISTER or the REGISTER AND IGNORE - * EXISTING KEY service action and is still registered by any - * initiator, all RESERVE commands and all RELEASE commands - * regardless of initiator shall conflict and shall terminate - * with a RESERVATION CONFLICT status. - */ - spin_lock(&pr_tmpl->registration_lock); - conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1; - spin_unlock(&pr_tmpl->registration_lock); - } - - if (conflict) { - pr_err("Received legacy SPC-2 RESERVE/RELEASE" - " while active SPC-3 registrations exist," - " returning RESERVATION_CONFLICT\n"); - return PYX_TRANSPORT_RESERVATION_CONFLICT; - } - -after_crh: - if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10)) - return core_scsi2_reservation_reserve(cmd); - else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10)) - return core_scsi2_reservation_release(cmd); - else - return PYX_TRANSPORT_INVALID_CDB_FIELD; -} /* * Begin SPC-3/SPC-4 Persistent Reservations emulation support @@ -418,12 +413,12 @@ static int core_scsi3_pr_seq_non_holder( break; case RELEASE: case RELEASE_10: - /* Handled by CRH=1 in core_scsi2_emulate_crh() */ + /* Handled by CRH=1 in target_scsi2_reservation_release() */ ret = 0; break; case RESERVE: case RESERVE_10: - /* Handled by CRH=1 in core_scsi2_emulate_crh() */ + /* Handled by CRH=1 in target_scsi2_reservation_reserve() */ ret = 0; break; case TEST_UNIT_READY: diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index c8f47d064584..4e94a427e314 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -47,7 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache; extern int core_pr_dump_initiator_port(struct t10_pr_registration *, char *, u32); -extern int core_scsi2_emulate_crh(struct se_cmd *); +extern int target_scsi2_reservation_release(struct se_cmd *cmd); +extern int target_scsi2_reservation_reserve(struct se_cmd *cmd); extern int core_scsi3_alloc_aptpl_registration( struct t10_reservation *, u64, unsigned char *, unsigned char *, u32, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index e84b26ffb17b..f4232934bac5 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2963,10 +2963,10 @@ static int transport_generic_cmd_sequencer( * is running in SPC_PASSTHROUGH, and wants reservations * emulation disabled. */ - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type != - SPC_PASSTHROUGH) ? - core_scsi2_emulate_crh : NULL; + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) { + cmd->transport_emulate_cdb = + target_scsi2_reservation_reserve; + } cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case RELEASE: @@ -2980,10 +2980,10 @@ static int transport_generic_cmd_sequencer( else size = cmd->data_length; - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type != - SPC_PASSTHROUGH) ? - core_scsi2_emulate_crh : NULL; + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) { + cmd->transport_emulate_cdb = + target_scsi2_reservation_release; + } cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case SYNCHRONIZE_CACHE: From 617c0e06c1b30b799d8b25f92eefdc1b098cb9f8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 3 Nov 2011 17:50:41 -0400 Subject: [PATCH 1392/1596] target: split core_scsi3_emulate_pr Split core_scsi2_emulate_crh into one routine each for the PERSISTENT_RESERVE_IN and PERSISTENT_RESERVE_OUT side. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_pr.c | 62 +++++++++++++++----------- drivers/target/target_core_pr.h | 4 +- drivers/target/target_core_transport.c | 11 +++-- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 830953a743d6..34403e80b87c 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -3734,12 +3734,30 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) /* * See spc4r17 section 6.14 Table 170 */ -static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) +int target_scsi3_emulate_pr_out(struct se_cmd *cmd) { + unsigned char *cdb = &cmd->t_task_cdb[0]; unsigned char *buf; u64 res_key, sa_res_key; int sa, scope, type, aptpl; int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; + + /* + * Following spc2r20 5.5.1 Reservations overview: + * + * If a logical unit has been reserved by any RESERVE command and is + * still reserved by any initiator, all PERSISTENT RESERVE IN and all + * PERSISTENT RESERVE OUT commands shall conflict regardless of + * initiator or service action and shall terminate with a RESERVATION + * CONFLICT status. + */ + if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { + pr_err("Received PERSISTENT_RESERVE CDB while legacy" + " SPC-2 reservation is held, returning" + " RESERVATION_CONFLICT\n"); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* * FIXME: A NULL struct se_session pointer means an this is not coming from * a $FABRIC_MOD's nexus, but from internal passthrough ops. @@ -4185,29 +4203,8 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) return 0; } -static int core_scsi3_emulate_pr_in(struct se_cmd *cmd, unsigned char *cdb) -{ - switch (cdb[1] & 0x1f) { - case PRI_READ_KEYS: - return core_scsi3_pri_read_keys(cmd); - case PRI_READ_RESERVATION: - return core_scsi3_pri_read_reservation(cmd); - case PRI_REPORT_CAPABILITIES: - return core_scsi3_pri_report_capabilities(cmd); - case PRI_READ_FULL_STATUS: - return core_scsi3_pri_read_full_status(cmd); - default: - pr_err("Unknown PERSISTENT_RESERVE_IN service" - " action: 0x%02x\n", cdb[1] & 0x1f); - return PYX_TRANSPORT_INVALID_CDB_FIELD; - } - -} - -int core_scsi3_emulate_pr(struct se_cmd *cmd) +int target_scsi3_emulate_pr_in(struct se_cmd *cmd) { - unsigned char *cdb = &cmd->t_task_cdb[0]; - struct se_device *dev = cmd->se_dev; /* * Following spc2r20 5.5.1 Reservations overview: * @@ -4217,16 +4214,27 @@ int core_scsi3_emulate_pr(struct se_cmd *cmd) * initiator or service action and shall terminate with a RESERVATION * CONFLICT status. */ - if (dev->dev_flags & DF_SPC2_RESERVATIONS) { + if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) { pr_err("Received PERSISTENT_RESERVE CDB while legacy" " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); return PYX_TRANSPORT_RESERVATION_CONFLICT; } - return (cdb[0] == PERSISTENT_RESERVE_OUT) ? - core_scsi3_emulate_pr_out(cmd, cdb) : - core_scsi3_emulate_pr_in(cmd, cdb); + switch (cmd->t_task_cdb[1] & 0x1f) { + case PRI_READ_KEYS: + return core_scsi3_pri_read_keys(cmd); + case PRI_READ_RESERVATION: + return core_scsi3_pri_read_reservation(cmd); + case PRI_REPORT_CAPABILITIES: + return core_scsi3_pri_report_capabilities(cmd); + case PRI_READ_FULL_STATUS: + return core_scsi3_pri_read_full_status(cmd); + default: + pr_err("Unknown PERSISTENT_RESERVE_IN service" + " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } } static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index 4e94a427e314..c9acb1108124 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -62,7 +62,9 @@ extern void core_scsi3_free_all_registrations(struct se_device *); extern unsigned char *core_scsi3_pr_dump_type(int); extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *, struct se_cmd *); -extern int core_scsi3_emulate_pr(struct se_cmd *); + +extern int target_scsi3_emulate_pr_in(struct se_cmd *cmd); +extern int target_scsi3_emulate_pr_out(struct se_cmd *cmd); extern int core_setup_reservations(struct se_device *, int); #endif /* TARGET_CORE_PR_H */ diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f4232934bac5..717f84a9b42b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2842,11 +2842,14 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case PERSISTENT_RESERVE_IN: + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->transport_emulate_cdb = target_scsi3_emulate_pr_in; + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; case PERSISTENT_RESERVE_OUT: - cmd->transport_emulate_cdb = - (su_dev->t10_pr.res_type == - SPC3_PERSISTENT_RESERVATIONS) ? - core_scsi3_emulate_pr : NULL; + if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) + cmd->transport_emulate_cdb = target_scsi3_emulate_pr_out; size = (cdb[7] << 8) + cdb[8]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; From e76a35d6c809bd1638e3b1b535bb780ac731c380 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 3 Nov 2011 17:50:42 -0400 Subject: [PATCH 1393/1596] target: pass the se_task to the CDB emulation callback We want to be able to handle all CDBs through it and remove hacks like always using the first task in a CDB in target_report_luns. Also rename the callback to ->execute_task to better describe its use. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 6 ++-- drivers/target/target_core_alua.h | 4 +-- drivers/target/target_core_device.c | 12 ++----- drivers/target/target_core_pr.c | 13 ++++--- drivers/target/target_core_pr.h | 8 ++--- drivers/target/target_core_transport.c | 50 ++++++++++---------------- include/target/target_core_base.h | 2 +- include/target/target_core_device.h | 2 +- 8 files changed, 42 insertions(+), 55 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 8f4447749c71..14668d05ea0d 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -58,8 +58,9 @@ struct t10_alua_lu_gp *default_lu_gp; * * See spc4r17 section 6.27 */ -int core_emulate_report_target_port_groups(struct se_cmd *cmd) +int target_emulate_report_target_port_groups(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; struct se_port *port; struct t10_alua_tg_pt_gp *tg_pt_gp; @@ -172,8 +173,9 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd) * * See spc4r17 section 6.35 */ -int core_emulate_set_target_port_groups(struct se_cmd *cmd) +int target_emulate_set_target_port_groups(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct se_port *port, *l_port = cmd->se_lun->lun_sep; diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index c86f97a081ed..c5b4ecd3e745 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -66,8 +66,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -extern int core_emulate_report_target_port_groups(struct se_cmd *); -extern int core_emulate_set_target_port_groups(struct se_cmd *); +extern int target_emulate_report_target_port_groups(struct se_task *); +extern int target_emulate_set_target_port_groups(struct se_task *); extern int core_alua_check_nonop_delay(struct se_cmd *); extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, struct se_device *, struct se_port *, diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index f870c3bcfd82..ffbb1d6532e9 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -651,23 +651,15 @@ void core_dev_unexport( lun->lun_se_dev = NULL; } -int transport_core_report_lun_response(struct se_cmd *se_cmd) +int target_report_luns(struct se_task *se_task) { + struct se_cmd *se_cmd = se_task->task_se_cmd; struct se_dev_entry *deve; struct se_lun *se_lun; struct se_session *se_sess = se_cmd->se_sess; - struct se_task *se_task; unsigned char *buf; u32 cdb_offset = 0, lun_count = 0, offset = 8, i; - list_for_each_entry(se_task, &se_cmd->t_task_list, t_list) - break; - - if (!se_task) { - pr_err("Unable to locate struct se_task for struct se_cmd\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; - } - buf = transport_kmap_first_data_page(se_cmd); /* diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 34403e80b87c..09e1e3e896c6 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -198,8 +198,9 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret) return false; } -int target_scsi2_reservation_release(struct se_cmd *cmd) +int target_scsi2_reservation_release(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg = sess->se_tpg; @@ -235,8 +236,9 @@ int target_scsi2_reservation_release(struct se_cmd *cmd) return 0; } -int target_scsi2_reservation_reserve(struct se_cmd *cmd) +int target_scsi2_reservation_reserve(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg = sess->se_tpg; @@ -3734,8 +3736,9 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) /* * See spc4r17 section 6.14 Table 170 */ -int target_scsi3_emulate_pr_out(struct se_cmd *cmd) +int target_scsi3_emulate_pr_out(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; unsigned char *cdb = &cmd->t_task_cdb[0]; unsigned char *buf; u64 res_key, sa_res_key; @@ -4203,8 +4206,10 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) return 0; } -int target_scsi3_emulate_pr_in(struct se_cmd *cmd) +int target_scsi3_emulate_pr_in(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; + /* * Following spc2r20 5.5.1 Reservations overview: * diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index c9acb1108124..b97f6940dd05 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -47,8 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache; extern int core_pr_dump_initiator_port(struct t10_pr_registration *, char *, u32); -extern int target_scsi2_reservation_release(struct se_cmd *cmd); -extern int target_scsi2_reservation_reserve(struct se_cmd *cmd); +extern int target_scsi2_reservation_release(struct se_task *task); +extern int target_scsi2_reservation_reserve(struct se_task *task); extern int core_scsi3_alloc_aptpl_registration( struct t10_reservation *, u64, unsigned char *, unsigned char *, u32, @@ -63,8 +63,8 @@ extern unsigned char *core_scsi3_pr_dump_type(int); extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *, struct se_cmd *); -extern int target_scsi3_emulate_pr_in(struct se_cmd *cmd); -extern int target_scsi3_emulate_pr_out(struct se_cmd *cmd); +extern int target_scsi3_emulate_pr_in(struct se_task *task); +extern int target_scsi3_emulate_pr_out(struct se_task *task); extern int core_setup_reservations(struct se_device *, int); #endif /* TARGET_CORE_PR_H */ diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 717f84a9b42b..3ad8db2d3ad3 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2156,12 +2156,12 @@ static int __transport_execute_tasks(struct se_device *dev) spin_unlock_irqrestore(&cmd->t_state_lock, flags); /* - * The struct se_cmd->transport_emulate_cdb() function pointer is used + * The struct se_cmd->execute_task() function pointer is used * to grab REPORT_LUNS and other CDBs we want to handle before they hit the * struct se_subsystem_api->do_task() caller below. */ - if (cmd->transport_emulate_cdb) { - error = cmd->transport_emulate_cdb(cmd); + if (cmd->execute_task) { + error = cmd->execute_task(task); if (error != 0) { cmd->transport_error_status = error; spin_lock_irqsave(&cmd->t_state_lock, flags); @@ -2174,7 +2174,7 @@ static int __transport_execute_tasks(struct se_device *dev) goto check_depth; } /* - * Handle the successful completion for transport_emulate_cdb() + * Handle the successful completion for execute_task() * for synchronous operation, following SCF_EMULATE_CDB_ASYNC * Otherwise the caller is expected to complete the task with * proper status. @@ -2795,12 +2795,10 @@ static int transport_generic_cmd_sequencer( /* * Check for emulated MI_REPORT_TARGET_PGS. */ - if (cdb[1] == MI_REPORT_TARGET_PGS) { - cmd->transport_emulate_cdb = - (su_dev->t10_alua.alua_type == - SPC3_ALUA_EMULATED) ? - core_emulate_report_target_port_groups : - NULL; + if (cdb[1] == MI_REPORT_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_task = + target_emulate_report_target_port_groups; } size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; @@ -2843,13 +2841,13 @@ static int transport_generic_cmd_sequencer( break; case PERSISTENT_RESERVE_IN: if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) - cmd->transport_emulate_cdb = target_scsi3_emulate_pr_in; + cmd->execute_task = target_scsi3_emulate_pr_in; size = (cdb[7] << 8) + cdb[8]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case PERSISTENT_RESERVE_OUT: if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) - cmd->transport_emulate_cdb = target_scsi3_emulate_pr_out; + cmd->execute_task = target_scsi3_emulate_pr_out; size = (cdb[7] << 8) + cdb[8]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; @@ -2868,12 +2866,10 @@ static int transport_generic_cmd_sequencer( * * Check for emulated MO_SET_TARGET_PGS. */ - if (cdb[1] == MO_SET_TARGET_PGS) { - cmd->transport_emulate_cdb = - (su_dev->t10_alua.alua_type == - SPC3_ALUA_EMULATED) ? - core_emulate_set_target_port_groups : - NULL; + if (cdb[1] == MO_SET_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_task = + target_emulate_set_target_port_groups; } size = (cdb[6] << 24) | (cdb[7] << 16) | @@ -2966,10 +2962,8 @@ static int transport_generic_cmd_sequencer( * is running in SPC_PASSTHROUGH, and wants reservations * emulation disabled. */ - if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) { - cmd->transport_emulate_cdb = - target_scsi2_reservation_reserve; - } + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_task = target_scsi2_reservation_reserve; cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case RELEASE: @@ -2983,10 +2977,8 @@ static int transport_generic_cmd_sequencer( else size = cmd->data_length; - if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) { - cmd->transport_emulate_cdb = - target_scsi2_reservation_release; - } + if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) + cmd->execute_task = target_scsi2_reservation_release; cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case SYNCHRONIZE_CACHE: @@ -3007,9 +2999,6 @@ static int transport_generic_cmd_sequencer( size = transport_get_size(sectors, cdb, cmd); cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - /* - * For TCM/pSCSI passthrough, skip cmd->transport_emulate_cdb() - */ if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) break; /* @@ -3086,8 +3075,7 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case REPORT_LUNS: - cmd->transport_emulate_cdb = - transport_core_report_lun_response; + cmd->execute_task = target_report_luns; size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; /* * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index dd245b68be5a..14c1a71a36eb 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -457,7 +457,7 @@ struct se_cmd { struct list_head se_cmd_list; struct completion cmd_wait_comp; struct target_core_fabric_ops *se_tfo; - int (*transport_emulate_cdb)(struct se_cmd *); + int (*execute_task)(struct se_task *); void (*transport_complete_callback)(struct se_cmd *); unsigned char *t_task_cdb; diff --git a/include/target/target_core_device.h b/include/target/target_core_device.h index 46571912086c..2be31ff8763b 100644 --- a/include/target/target_core_device.h +++ b/include/target/target_core_device.h @@ -17,7 +17,7 @@ extern int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); extern void core_dev_unexport(struct se_device *, struct se_portal_group *, struct se_lun *); -extern int transport_core_report_lun_response(struct se_cmd *); +extern int target_report_luns(struct se_task *); extern void se_release_device_for_hba(struct se_device *); extern void se_release_vpd_for_dev(struct se_device *); extern void se_clear_dev_ports(struct se_device *); From 6ed5a557905f1c4e9ca5f8a6d607303a12d097e1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 3 Nov 2011 17:50:43 -0400 Subject: [PATCH 1394/1596] target: refactor transport_emulate_control_cdb Encapsulate each CDB emulation into a function of its own, to prepare setting ->exectute_task to these routines. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_cdb.c | 105 +++++++++++++++++-------------- 1 file changed, 59 insertions(+), 46 deletions(-) diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 38535eb13929..ff2dfa383735 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -680,8 +680,9 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) } static int -target_emulate_inquiry(struct se_cmd *cmd) +target_emulate_inquiry(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned char *cdb = cmd->t_task_cdb; @@ -721,8 +722,9 @@ target_emulate_inquiry(struct se_cmd *cmd) } static int -target_emulate_readcapacity(struct se_cmd *cmd) +target_emulate_readcapacity(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned long long blocks_long = dev->transport->get_blocks(dev); @@ -755,8 +757,9 @@ target_emulate_readcapacity(struct se_cmd *cmd) } static int -target_emulate_readcapacity_16(struct se_cmd *cmd) +target_emulate_readcapacity_16(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned long long blocks = dev->transport->get_blocks(dev); @@ -923,13 +926,15 @@ target_modesense_dpofua(unsigned char *buf, int type) } static int -target_emulate_modesense(struct se_cmd *cmd, int ten) +target_emulate_modesense(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; char *cdb = cmd->t_task_cdb; unsigned char *rbuf; int type = dev->transport->get_device_type(dev); - int offset = (ten) ? 8 : 4; + int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10); + int offset = ten ? 8 : 4; int length = 0; unsigned char buf[SE_MODE_PAGE_BUF]; @@ -999,8 +1004,9 @@ target_emulate_modesense(struct se_cmd *cmd, int ten) } static int -target_emulate_request_sense(struct se_cmd *cmd) +target_emulate_request_sense(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; unsigned char *cdb = cmd->t_task_cdb; unsigned char *buf; u8 ua_asc = 0, ua_ascq = 0; @@ -1079,6 +1085,12 @@ target_emulate_unmap(struct se_task *task) int ret = 0, offset; unsigned short dl, bd_dl; + if (!dev->transport->do_discard) { + pr_err("UNMAP emulation not supported for: %s\n", + dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + /* First UNMAP block descriptor starts at 8 byte offset */ offset = 8; size -= 8; @@ -1119,13 +1131,28 @@ target_emulate_unmap(struct se_task *task) * Note this is not used for TCM/pSCSI passthrough */ static int -target_emulate_write_same(struct se_task *task, u32 num_blocks) +target_emulate_write_same(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; sector_t range; sector_t lba = cmd->t_task_lba; + u32 num_blocks; int ret; + + if (!dev->transport->do_discard) { + pr_err("WRITE_SAME emulation not supported" + " for: %s\n", dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + + if (cmd->t_task_cdb[0] == WRITE_SAME) + num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]); + else if (cmd->t_task_cdb[0] == WRITE_SAME_16) + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]); + else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */ + num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]); + /* * Use the explicit range when non zero is supplied, otherwise calculate * the remaining range based on ->get_blocks() - starting LBA. @@ -1147,6 +1174,21 @@ target_emulate_write_same(struct se_task *task, u32 num_blocks) return 0; } +static int +target_emulate_synchronize_cache(struct se_task *task) +{ + struct se_device *dev = task->task_se_cmd->se_dev; + + if (!dev->transport->do_sync_cache) { + pr_err("SYNCHRONIZE_CACHE emulation not supported" + " for: %s\n", dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + + dev->transport->do_sync_cache(task); + return 0; +} + int transport_emulate_control_cdb(struct se_task *task) { @@ -1157,21 +1199,21 @@ transport_emulate_control_cdb(struct se_task *task) switch (cmd->t_task_cdb[0]) { case INQUIRY: - ret = target_emulate_inquiry(cmd); + ret = target_emulate_inquiry(task); break; case READ_CAPACITY: - ret = target_emulate_readcapacity(cmd); + ret = target_emulate_readcapacity(task); break; case MODE_SENSE: - ret = target_emulate_modesense(cmd, 0); + ret = target_emulate_modesense(task); break; case MODE_SENSE_10: - ret = target_emulate_modesense(cmd, 1); + ret = target_emulate_modesense(task); break; case SERVICE_ACTION_IN: switch (cmd->t_task_cdb[1] & 0x1f) { case SAI_READ_CAPACITY_16: - ret = target_emulate_readcapacity_16(cmd); + ret = target_emulate_readcapacity_16(task); break; default: pr_err("Unsupported SA: 0x%02x\n", @@ -1180,47 +1222,23 @@ transport_emulate_control_cdb(struct se_task *task) } break; case REQUEST_SENSE: - ret = target_emulate_request_sense(cmd); + ret = target_emulate_request_sense(task); break; case UNMAP: - if (!dev->transport->do_discard) { - pr_err("UNMAP emulation not supported for: %s\n", - dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } ret = target_emulate_unmap(task); break; case WRITE_SAME: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be16(&cmd->t_task_cdb[7])); + ret = target_emulate_write_same(task); break; case WRITE_SAME_16: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME_16 emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be32(&cmd->t_task_cdb[10])); + ret = target_emulate_write_same(task); break; case VARIABLE_LENGTH_CMD: service_action = get_unaligned_be16(&cmd->t_task_cdb[8]); switch (service_action) { case WRITE_SAME_32: - if (!dev->transport->do_discard) { - pr_err("WRITE_SAME_32 SA emulation not" - " supported for: %s\n", - dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - ret = target_emulate_write_same(task, - get_unaligned_be32(&cmd->t_task_cdb[28])); + ret = target_emulate_write_same(task); break; default: pr_err("Unsupported VARIABLE_LENGTH_CMD SA:" @@ -1230,12 +1248,7 @@ transport_emulate_control_cdb(struct se_task *task) break; case SYNCHRONIZE_CACHE: case 0x91: /* SYNCHRONIZE_CACHE_16: */ - if (!dev->transport->do_sync_cache) { - pr_err("SYNCHRONIZE_CACHE emulation not supported" - " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - dev->transport->do_sync_cache(task); + ret = target_emulate_synchronize_cache(task); break; case ALLOW_MEDIUM_REMOVAL: case ERASE: From c9a1be96277b3b2d2e8aff2ba69d7817ea8e46c9 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 3 Nov 2011 11:16:49 -0400 Subject: [PATCH 1395/1596] drm/radeon/kms: consolidate GART code, fix segfault after GPU lockup V2 After GPU lockup VRAM gart table is unpinned and thus its pointer becomes unvalid. This patch move the unpin code to a common helper function and set pointer to NULL so that page update code can check if it should update GPU page table or not. That way bo still bound to GART can be unbound (pci_unmap_page for all there page) properly while there is no need to update the GPU page table. V2 move the test for null gart out of the loop, small optimization Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 12 +---- drivers/gpu/drm/radeon/ni.c | 13 +---- drivers/gpu/drm/radeon/r100.c | 6 ++- drivers/gpu/drm/radeon/r300.c | 16 ++----- drivers/gpu/drm/radeon/r600.c | 17 ++----- drivers/gpu/drm/radeon/radeon.h | 22 ++------- drivers/gpu/drm/radeon/radeon_gart.c | 71 +++++++++++++++++----------- drivers/gpu/drm/radeon/rs400.c | 5 +- drivers/gpu/drm/radeon/rs600.c | 16 ++----- drivers/gpu/drm/radeon/rv770.c | 13 ++--- 10 files changed, 75 insertions(+), 116 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 7ce9c87e695e..e4c384b9511c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -894,7 +894,7 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -946,7 +946,6 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) void evergreen_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); @@ -966,14 +965,7 @@ void evergreen_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void evergreen_pcie_gart_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 722cfb398992..8402661fc206 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -935,7 +935,7 @@ int cayman_pcie_gart_enable(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -980,8 +980,6 @@ int cayman_pcie_gart_enable(struct radeon_device *rdev) void cayman_pcie_gart_disable(struct radeon_device *rdev) { - int r; - /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); WREG32(VM_CONTEXT1_CNTL, 0); @@ -997,14 +995,7 @@ void cayman_pcie_gart_disable(struct radeon_device *rdev) WREG32(VM_L2_CNTL2, 0); WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY | L2_CACHE_BIGK_FRAGMENT_SIZE(6)); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void cayman_pcie_gart_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 4191eaf47381..6d7766260419 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -577,7 +577,7 @@ int r100_pci_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.ram.ptr) { + if (rdev->gart.ptr) { WARN(1, "R100 PCI GART already initialized\n"); return 0; } @@ -636,10 +636,12 @@ void r100_pci_gart_disable(struct radeon_device *rdev) int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { + u32 *gtt = rdev->gart.ptr; + if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; } - rdev->gart.table.ram.ptr[i] = cpu_to_le32(lower_32_bits(addr)); + gtt[i] = cpu_to_le32(lower_32_bits(addr)); return 0; } diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 33f2b68c680b..400b26df652a 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -74,7 +74,7 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; @@ -93,7 +93,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "RV370 PCIE GART already initialized\n"); return 0; } @@ -116,7 +116,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) uint32_t tmp; int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -154,7 +154,6 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) void rv370_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0); WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0); @@ -163,14 +162,7 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rv370_pcie_gart_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index ff3ae48aa1a7..06f7682c87c7 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -895,7 +895,7 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) /* flush hdp cache so updates hit vram */ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) && !(rdev->flags & RADEON_IS_AGP)) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = (void *)rdev->gart.ptr; u32 tmp; /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read @@ -930,7 +930,7 @@ int r600_pcie_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "R600 PCIE GART already initialized\n"); return 0; } @@ -947,7 +947,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -1002,7 +1002,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev) void r600_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int i, r; + int i; /* Disable all tables */ for (i = 0; i < 7; i++) @@ -1029,14 +1029,7 @@ void r600_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void r600_pcie_gart_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e94c6f18a157..b316b301152f 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -307,30 +307,17 @@ int radeon_mode_dumb_destroy(struct drm_file *file_priv, */ struct radeon_mc; -struct radeon_gart_table_ram { - volatile uint32_t *ptr; -}; - -struct radeon_gart_table_vram { - struct radeon_bo *robj; - volatile uint32_t *ptr; -}; - -union radeon_gart_table { - struct radeon_gart_table_ram ram; - struct radeon_gart_table_vram vram; -}; - #define RADEON_GPU_PAGE_SIZE 4096 #define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1) #define RADEON_GPU_PAGE_SHIFT 12 struct radeon_gart { dma_addr_t table_addr; + struct radeon_bo *robj; + void *ptr; unsigned num_gpu_pages; unsigned num_cpu_pages; unsigned table_size; - union radeon_gart_table table; struct page **pages; dma_addr_t *pages_addr; bool *ttm_alloced; @@ -341,6 +328,8 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev); void radeon_gart_table_ram_free(struct radeon_device *rdev); int radeon_gart_table_vram_alloc(struct radeon_device *rdev); void radeon_gart_table_vram_free(struct radeon_device *rdev); +int radeon_gart_table_vram_pin(struct radeon_device *rdev); +void radeon_gart_table_vram_unpin(struct radeon_device *rdev); int radeon_gart_init(struct radeon_device *rdev); void radeon_gart_fini(struct radeon_device *rdev); void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, @@ -348,6 +337,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int pages, struct page **pagelist, dma_addr_t *dma_addr); +void radeon_gart_restore(struct radeon_device *rdev); /* @@ -1445,8 +1435,6 @@ void radeon_ring_write(struct radeon_device *rdev, uint32_t v); /* AGP */ extern int radeon_gpu_reset(struct radeon_device *rdev); extern void radeon_agp_disable(struct radeon_device *rdev); -extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); -extern void radeon_gart_restore(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev); extern bool radeon_card_posted(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index fdc3a9a54bf8..ba7ab79e12c1 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -49,27 +49,27 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev) rdev->gart.table_size >> PAGE_SHIFT); } #endif - rdev->gart.table.ram.ptr = ptr; - memset((void *)rdev->gart.table.ram.ptr, 0, rdev->gart.table_size); + rdev->gart.ptr = ptr; + memset((void *)rdev->gart.ptr, 0, rdev->gart.table_size); return 0; } void radeon_gart_table_ram_free(struct radeon_device *rdev) { - if (rdev->gart.table.ram.ptr == NULL) { + if (rdev->gart.ptr == NULL) { return; } #ifdef CONFIG_X86 if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { - set_memory_wb((unsigned long)rdev->gart.table.ram.ptr, + set_memory_wb((unsigned long)rdev->gart.ptr, rdev->gart.table_size >> PAGE_SHIFT); } #endif pci_free_consistent(rdev->pdev, rdev->gart.table_size, - (void *)rdev->gart.table.ram.ptr, + (void *)rdev->gart.ptr, rdev->gart.table_addr); - rdev->gart.table.ram.ptr = NULL; + rdev->gart.ptr = NULL; rdev->gart.table_addr = 0; } @@ -77,10 +77,10 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { r = radeon_bo_create(rdev, rdev->gart.table_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, - &rdev->gart.table.vram.robj); + &rdev->gart.robj); if (r) { return r; } @@ -93,38 +93,46 @@ int radeon_gart_table_vram_pin(struct radeon_device *rdev) uint64_t gpu_addr; int r; - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); + r = radeon_bo_reserve(rdev->gart.robj, false); if (unlikely(r != 0)) return r; - r = radeon_bo_pin(rdev->gart.table.vram.robj, + r = radeon_bo_pin(rdev->gart.robj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr); if (r) { - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_unreserve(rdev->gart.robj); return r; } - r = radeon_bo_kmap(rdev->gart.table.vram.robj, - (void **)&rdev->gart.table.vram.ptr); + r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr); if (r) - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_unpin(rdev->gart.robj); + radeon_bo_unreserve(rdev->gart.robj); rdev->gart.table_addr = gpu_addr; return r; } -void radeon_gart_table_vram_free(struct radeon_device *rdev) +void radeon_gart_table_vram_unpin(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { return; } - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); + r = radeon_bo_reserve(rdev->gart.robj, false); if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_kunmap(rdev->gart.robj); + radeon_bo_unpin(rdev->gart.robj); + radeon_bo_unreserve(rdev->gart.robj); + rdev->gart.ptr = NULL; } - radeon_bo_unref(&rdev->gart.table.vram.robj); +} + +void radeon_gart_table_vram_free(struct radeon_device *rdev) +{ + if (rdev->gart.robj == NULL) { + return; + } + radeon_gart_table_vram_unpin(rdev); + radeon_bo_unref(&rdev->gart.robj); } @@ -151,12 +159,14 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, if (rdev->gart.pages[p]) { if (!rdev->gart.ttm_alloced[p]) pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); rdev->gart.pages[p] = NULL; rdev->gart.pages_addr[p] = rdev->dummy_page.addr; page_base = rdev->gart.pages_addr[p]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); + if (rdev->gart.ptr) { + radeon_gart_set_page(rdev, t, page_base); + } page_base += RADEON_GPU_PAGE_SIZE; } } @@ -199,10 +209,12 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, } } rdev->gart.pages[p] = pagelist[i]; - page_base = rdev->gart.pages_addr[p]; - for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); - page_base += RADEON_GPU_PAGE_SIZE; + if (rdev->gart.ptr) { + page_base = rdev->gart.pages_addr[p]; + for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + radeon_gart_set_page(rdev, t, page_base); + page_base += RADEON_GPU_PAGE_SIZE; + } } } mb(); @@ -215,6 +227,9 @@ void radeon_gart_restore(struct radeon_device *rdev) int i, j, t; u64 page_base; + if (!rdev->gart.ptr) { + return; + } for (i = 0, t = 0; i < rdev->gart.num_cpu_pages; i++) { page_base = rdev->gart.pages_addr[i]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 89a6e1ecea8d..06b90c87f8f3 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -77,7 +77,7 @@ int rs400_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.ram.ptr) { + if (rdev->gart.ptr) { WARN(1, "RS400 GART already initialized\n"); return 0; } @@ -212,6 +212,7 @@ void rs400_gart_fini(struct radeon_device *rdev) int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { uint32_t entry; + u32 *gtt = rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; @@ -221,7 +222,7 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) ((upper_32_bits(addr) & 0xff) << 4) | RS400_PTE_WRITEABLE | RS400_PTE_READABLE; entry = cpu_to_le32(entry); - rdev->gart.table.ram.ptr[i] = entry; + gtt[i] = entry; return 0; } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 02e0390daa8e..481b99e89f65 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -414,7 +414,7 @@ int rs600_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "RS600 GART already initialized\n"); return 0; } @@ -432,7 +432,7 @@ static int rs600_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -495,20 +495,12 @@ static int rs600_gart_enable(struct radeon_device *rdev) void rs600_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; /* FIXME: disable out of gart access */ WREG32_MC(R_000100_MC_PT0_CNTL, 0); tmp = RREG32_MC(R_000009_MC_CNTL1); WREG32_MC(R_000009_MC_CNTL1, tmp & C_000009_ENABLE_PAGE_TABLES); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (r == 0) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rs600_gart_fini(struct radeon_device *rdev) @@ -526,7 +518,7 @@ void rs600_gart_fini(struct radeon_device *rdev) int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = (void *)rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index a09049d15901..a983f410ab89 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -124,7 +124,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -171,7 +171,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) void rv770_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int i, r; + int i; /* Disable all tables */ for (i = 0; i < 7; i++) @@ -191,14 +191,7 @@ void rv770_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rv770_pcie_gart_fini(struct radeon_device *rdev) From d29a5b6acc4b63d4e05ff554509df6fbeaf527cd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 3 Nov 2011 17:50:44 -0400 Subject: [PATCH 1396/1596] target: remove SCF_EMULATE_CDB_ASYNC All ->execute_task instances now need to complete the I/O explicitly, which can either happen synchronously or asynchronously. Note that a lot of the CDB emulations appear to return success even if some lowlevel operations failed. Given that this is an existing issue this patch doesn't change that fact. (nab: Adding missing switch breaks in PR-IN + PR_OUT) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 5 +- drivers/target/target_core_cdb.c | 58 +++++++---- drivers/target/target_core_device.c | 2 + drivers/target/target_core_pr.c | 129 ++++++++++++++++--------- drivers/target/target_core_transport.c | 47 ++------- include/target/target_core_base.h | 1 - 6 files changed, 142 insertions(+), 100 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 14668d05ea0d..2739b93983a2 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -165,6 +165,8 @@ int target_emulate_report_target_port_groups(struct se_task *task) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -343,7 +345,8 @@ int target_emulate_set_target_port_groups(struct se_task *task) out: transport_kunmap_first_data_page(cmd); - + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index ff2dfa383735..5a03085304e5 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -688,8 +688,10 @@ target_emulate_inquiry(struct se_task *task) unsigned char *cdb = cmd->t_task_cdb; int p, ret; - if (!(cdb[1] & 0x1)) - return target_emulate_inquiry_std(cmd); + if (!(cdb[1] & 0x1)) { + ret = target_emulate_inquiry_std(cmd); + goto out; + } /* * Make sure we at least have 4 bytes of INQUIRY response @@ -708,17 +710,25 @@ target_emulate_inquiry(struct se_task *task) buf[0] = dev->transport->get_device_type(dev); - for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) + for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) { if (cdb[2] == evpd_handlers[p].page) { buf[1] = cdb[2]; ret = evpd_handlers[p].emulate(cmd, buf); - transport_kunmap_first_data_page(cmd); - return ret; + goto out_unmap; } + } - transport_kunmap_first_data_page(cmd); pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); - return -EINVAL; + ret = -EINVAL; + +out_unmap: + transport_kunmap_first_data_page(cmd); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } static int @@ -753,6 +763,8 @@ target_emulate_readcapacity(struct se_task *task) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -787,6 +799,8 @@ target_emulate_readcapacity_16(struct se_task *task) transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -1000,6 +1014,8 @@ target_emulate_modesense(struct se_task *task) memcpy(rbuf, buf, offset); transport_kunmap_first_data_page(cmd); + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -1065,7 +1081,8 @@ target_emulate_request_sense(struct se_task *task) end: transport_kunmap_first_data_page(cmd); - + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -1122,7 +1139,10 @@ target_emulate_unmap(struct se_task *task) err: transport_kunmap_first_data_page(cmd); - + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } return ret; } @@ -1171,6 +1191,8 @@ target_emulate_write_same(struct se_task *task) return ret; } + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); return 0; } @@ -1189,6 +1211,14 @@ target_emulate_synchronize_cache(struct se_task *task) return 0; } +static int +target_emulate_noop(struct se_task *task) +{ + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + return 0; +} + int transport_emulate_control_cdb(struct se_task *task) { @@ -1259,6 +1289,7 @@ transport_emulate_control_cdb(struct se_task *task) case TEST_UNIT_READY: case VERIFY: case WRITE_FILEMARKS: + ret = target_emulate_noop(task); break; default: pr_err("Unsupported SCSI Opcode: 0x%02x for %s\n", @@ -1268,15 +1299,6 @@ transport_emulate_control_cdb(struct se_task *task) if (ret < 0) return ret; - /* - * Handle the successful completion here unless a caller - * has explictly requested an asychronous completion. - */ - if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } - return PYX_TRANSPORT_SENT_TO_TRANSPORT; } diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index ffbb1d6532e9..28d2c808c56b 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -705,6 +705,8 @@ int target_report_luns(struct se_task *se_task) buf[2] = ((lun_count >> 8) & 0xff); buf[3] = (lun_count & 0xff); + se_task->task_scsi_status = GOOD; + transport_complete_task(se_task, 1); return PYX_TRANSPORT_SENT_TO_TRANSPORT; } diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 09e1e3e896c6..5a4ebfc3a54f 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -204,23 +204,21 @@ int target_scsi2_reservation_release(struct se_task *task) struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg = sess->se_tpg; - int ret; + int ret = 0; if (!sess || !tpg) - return 0; + goto out; if (target_check_scsi2_reservation_conflict(cmd, &ret)) - return ret; + goto out; + ret = 0; spin_lock(&dev->dev_reservation_lock); - if (!dev->dev_reserved_node_acl || !sess) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } + if (!dev->dev_reserved_node_acl || !sess) + goto out_unlock; + + if (dev->dev_reserved_node_acl != sess->se_node_acl) + goto out_unlock; - if (dev->dev_reserved_node_acl != sess->se_node_acl) { - spin_unlock(&dev->dev_reservation_lock); - return 0; - } dev->dev_reserved_node_acl = NULL; dev->dev_flags &= ~DF_SPC2_RESERVATIONS; if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { @@ -231,9 +229,15 @@ int target_scsi2_reservation_release(struct se_task *task) " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - return 0; +out_unlock: + spin_unlock(&dev->dev_reservation_lock); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } int target_scsi2_reservation_reserve(struct se_task *task) @@ -242,23 +246,25 @@ int target_scsi2_reservation_reserve(struct se_task *task) struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg = sess->se_tpg; - int ret; + int ret = 0; if ((cmd->t_task_cdb[1] & 0x01) && (cmd->t_task_cdb[1] & 0x02)) { pr_err("LongIO and Obselete Bits set, returning" " ILLEGAL_REQUEST\n"); - return PYX_TRANSPORT_ILLEGAL_REQUEST; + ret = PYX_TRANSPORT_ILLEGAL_REQUEST; + goto out; } /* * This is currently the case for target_core_mod passthrough struct se_cmd * ops */ if (!sess || !tpg) - return 0; + goto out; if (target_check_scsi2_reservation_conflict(cmd, &ret)) - return ret; + goto out; + ret = 0; spin_lock(&dev->dev_reservation_lock); if (dev->dev_reserved_node_acl && (dev->dev_reserved_node_acl != sess->se_node_acl)) { @@ -271,8 +277,8 @@ int target_scsi2_reservation_reserve(struct se_task *task) " from %s \n", cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + goto out_unlock; } dev->dev_reserved_node_acl = sess->se_node_acl; @@ -285,9 +291,15 @@ int target_scsi2_reservation_reserve(struct se_task *task) " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, sess->se_node_acl->initiatorname); - spin_unlock(&dev->dev_reservation_lock); - return 0; +out_unlock: + spin_unlock(&dev->dev_reservation_lock); +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } @@ -3744,6 +3756,7 @@ int target_scsi3_emulate_pr_out(struct se_task *task) u64 res_key, sa_res_key; int sa, scope, type, aptpl; int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; + int ret; /* * Following spc2r20 5.5.1 Reservations overview: @@ -3758,7 +3771,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) pr_err("Received PERSISTENT_RESERVE CDB while legacy" " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + goto out; } /* @@ -3771,7 +3785,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) if (cmd->data_length < 24) { pr_warn("SPC-PR: Received PR OUT parameter list" " length too small: %u\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; } /* * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB) @@ -3804,8 +3819,11 @@ int target_scsi3_emulate_pr_out(struct se_task *task) /* * SPEC_I_PT=1 is only valid for Service action: REGISTER */ - if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) { + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + /* * From spc4r17 section 6.14: * @@ -3819,7 +3837,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) (cmd->data_length != 24)) { pr_warn("SPC-PR: Received PR OUT illegal parameter" " list length: %u\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; } /* * (core_scsi3_emulate_pro_* function parameters @@ -3828,35 +3847,47 @@ int target_scsi3_emulate_pr_out(struct se_task *task) */ switch (sa) { case PRO_REGISTER: - return core_scsi3_emulate_pro_register(cmd, + ret = core_scsi3_emulate_pro_register(cmd, res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0); + break; case PRO_RESERVE: - return core_scsi3_emulate_pro_reserve(cmd, - type, scope, res_key); + ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key); + break; case PRO_RELEASE: - return core_scsi3_emulate_pro_release(cmd, - type, scope, res_key); + ret = core_scsi3_emulate_pro_release(cmd, type, scope, res_key); + break; case PRO_CLEAR: - return core_scsi3_emulate_pro_clear(cmd, res_key); + ret = core_scsi3_emulate_pro_clear(cmd, res_key); + break; case PRO_PREEMPT: - return core_scsi3_emulate_pro_preempt(cmd, type, scope, + ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, res_key, sa_res_key, 0); + break; case PRO_PREEMPT_AND_ABORT: - return core_scsi3_emulate_pro_preempt(cmd, type, scope, + ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, res_key, sa_res_key, 1); + break; case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: - return core_scsi3_emulate_pro_register(cmd, + ret = core_scsi3_emulate_pro_register(cmd, 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1); + break; case PRO_REGISTER_AND_MOVE: - return core_scsi3_emulate_pro_register_and_move(cmd, res_key, + ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key, sa_res_key, aptpl, unreg); + break; default: pr_err("Unknown PERSISTENT_RESERVE_OUT service" " action: 0x%02x\n", cdb[1] & 0x1f); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + break; } - return PYX_TRANSPORT_INVALID_CDB_FIELD; +out: + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return ret; } /* @@ -4209,6 +4240,7 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) int target_scsi3_emulate_pr_in(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; + int ret; /* * Following spc2r20 5.5.1 Reservations overview: @@ -4228,18 +4260,29 @@ int target_scsi3_emulate_pr_in(struct se_task *task) switch (cmd->t_task_cdb[1] & 0x1f) { case PRI_READ_KEYS: - return core_scsi3_pri_read_keys(cmd); + ret = core_scsi3_pri_read_keys(cmd); + break; case PRI_READ_RESERVATION: - return core_scsi3_pri_read_reservation(cmd); + ret = core_scsi3_pri_read_reservation(cmd); + break; case PRI_REPORT_CAPABILITIES: - return core_scsi3_pri_report_capabilities(cmd); + ret = core_scsi3_pri_report_capabilities(cmd); + break; case PRI_READ_FULL_STATUS: - return core_scsi3_pri_read_full_status(cmd); + ret = core_scsi3_pri_read_full_status(cmd); + break; default: pr_err("Unknown PERSISTENT_RESERVE_IN service" " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + break; + } + + if (!ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); } + return ret; } static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3ad8db2d3ad3..74015793c03a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2162,28 +2162,6 @@ static int __transport_execute_tasks(struct se_device *dev) */ if (cmd->execute_task) { error = cmd->execute_task(task); - if (error != 0) { - cmd->transport_error_status = error; - spin_lock_irqsave(&cmd->t_state_lock, flags); - task->task_flags &= ~TF_ACTIVE; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - atomic_set(&cmd->t_transport_sent, 0); - transport_stop_tasks_for_cmd(cmd); - atomic_inc(&dev->depth_left); - transport_generic_request_failure(cmd, 0, 1); - goto check_depth; - } - /* - * Handle the successful completion for execute_task() - * for synchronous operation, following SCF_EMULATE_CDB_ASYNC - * Otherwise the caller is expected to complete the task with - * proper status. - */ - if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) { - cmd->scsi_status = SAM_STAT_GOOD; - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } } else { /* * Currently for all virtual TCM plugins including IBLOCK, FILEIO and @@ -2200,17 +2178,17 @@ static int __transport_execute_tasks(struct se_device *dev) error = transport_emulate_control_cdb(task); else error = dev->transport->do_task(task); + } - if (error != 0) { - cmd->transport_error_status = error; - spin_lock_irqsave(&cmd->t_state_lock, flags); - task->task_flags &= ~TF_ACTIVE; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - atomic_set(&cmd->t_transport_sent, 0); - transport_stop_tasks_for_cmd(cmd); - atomic_inc(&dev->depth_left); - transport_generic_request_failure(cmd, 0, 1); - } + if (error != 0) { + cmd->transport_error_status = error; + spin_lock_irqsave(&cmd->t_state_lock, flags); + task->task_flags &= ~TF_ACTIVE; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + atomic_set(&cmd->t_transport_sent, 0); + transport_stop_tasks_for_cmd(cmd); + atomic_inc(&dev->depth_left); + transport_generic_request_failure(cmd, 0, 1); } goto check_depth; @@ -3001,11 +2979,6 @@ static int transport_generic_cmd_sequencer( if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) break; - /* - * Set SCF_EMULATE_CDB_ASYNC to ensure asynchronous operation - * for SYNCHRONIZE_CACHE* Immed=1 case in __transport_execute_tasks() - */ - cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC; /* * Check to ensure that LBA + Range does not exceed past end of * device for IBLOCK and FILEIO ->do_sync_cache() backend calls diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 14c1a71a36eb..7f5fed3c89e1 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -114,7 +114,6 @@ enum se_cmd_flags_table { SCF_DELAYED_CMD_FROM_SAM_ATTR = 0x00080000, SCF_UNUSED = 0x00100000, SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000, - SCF_EMULATE_CDB_ASYNC = 0x01000000, }; /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ From 5bda90c8f20f0af93375721533f4081a40fa6f41 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 3 Nov 2011 17:50:45 -0400 Subject: [PATCH 1397/1596] target: use ->exectute_task for all CDB emulation Instead of calling into transport_emulate_control_cdb from __transport_execute_tasks for some CDBs always set up ->exectute_tasks in the command sequence and use it uniformly. (nab: Add default passthrough break for SERVICE_ACTION_IN) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_cdb.c | 111 +++--------------------- drivers/target/target_core_cdb.h | 14 ++++ drivers/target/target_core_transport.c | 112 ++++++++++++++++--------- 3 files changed, 97 insertions(+), 140 deletions(-) create mode 100644 drivers/target/target_core_cdb.h diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 5a03085304e5..683ba02b8247 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -32,6 +32,7 @@ #include #include #include "target_core_ua.h" +#include "target_core_cdb.h" static void target_fill_alua_data(struct se_port *port, unsigned char *buf) @@ -679,8 +680,7 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) return 0; } -static int -target_emulate_inquiry(struct se_task *task) +int target_emulate_inquiry(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; @@ -731,8 +731,7 @@ target_emulate_inquiry(struct se_task *task) return ret; } -static int -target_emulate_readcapacity(struct se_task *task) +int target_emulate_readcapacity(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; @@ -768,8 +767,7 @@ target_emulate_readcapacity(struct se_task *task) return 0; } -static int -target_emulate_readcapacity_16(struct se_task *task) +int target_emulate_readcapacity_16(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; @@ -939,8 +937,7 @@ target_modesense_dpofua(unsigned char *buf, int type) } } -static int -target_emulate_modesense(struct se_task *task) +int target_emulate_modesense(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; @@ -1019,8 +1016,7 @@ target_emulate_modesense(struct se_task *task) return 0; } -static int -target_emulate_request_sense(struct se_task *task) +int target_emulate_request_sense(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; unsigned char *cdb = cmd->t_task_cdb; @@ -1090,8 +1086,7 @@ target_emulate_request_sense(struct se_task *task) * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -static int -target_emulate_unmap(struct se_task *task) +int target_emulate_unmap(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; @@ -1150,8 +1145,7 @@ target_emulate_unmap(struct se_task *task) * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -static int -target_emulate_write_same(struct se_task *task) +int target_emulate_write_same(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; @@ -1196,8 +1190,7 @@ target_emulate_write_same(struct se_task *task) return 0; } -static int -target_emulate_synchronize_cache(struct se_task *task) +int target_emulate_synchronize_cache(struct se_task *task) { struct se_device *dev = task->task_se_cmd->se_dev; @@ -1211,97 +1204,13 @@ target_emulate_synchronize_cache(struct se_task *task) return 0; } -static int -target_emulate_noop(struct se_task *task) +int target_emulate_noop(struct se_task *task) { task->task_scsi_status = GOOD; transport_complete_task(task, 1); return 0; } -int -transport_emulate_control_cdb(struct se_task *task) -{ - struct se_cmd *cmd = task->task_se_cmd; - struct se_device *dev = cmd->se_dev; - unsigned short service_action; - int ret = 0; - - switch (cmd->t_task_cdb[0]) { - case INQUIRY: - ret = target_emulate_inquiry(task); - break; - case READ_CAPACITY: - ret = target_emulate_readcapacity(task); - break; - case MODE_SENSE: - ret = target_emulate_modesense(task); - break; - case MODE_SENSE_10: - ret = target_emulate_modesense(task); - break; - case SERVICE_ACTION_IN: - switch (cmd->t_task_cdb[1] & 0x1f) { - case SAI_READ_CAPACITY_16: - ret = target_emulate_readcapacity_16(task); - break; - default: - pr_err("Unsupported SA: 0x%02x\n", - cmd->t_task_cdb[1] & 0x1f); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - break; - case REQUEST_SENSE: - ret = target_emulate_request_sense(task); - break; - case UNMAP: - ret = target_emulate_unmap(task); - break; - case WRITE_SAME: - ret = target_emulate_write_same(task); - break; - case WRITE_SAME_16: - ret = target_emulate_write_same(task); - break; - case VARIABLE_LENGTH_CMD: - service_action = - get_unaligned_be16(&cmd->t_task_cdb[8]); - switch (service_action) { - case WRITE_SAME_32: - ret = target_emulate_write_same(task); - break; - default: - pr_err("Unsupported VARIABLE_LENGTH_CMD SA:" - " 0x%02x\n", service_action); - break; - } - break; - case SYNCHRONIZE_CACHE: - case 0x91: /* SYNCHRONIZE_CACHE_16: */ - ret = target_emulate_synchronize_cache(task); - break; - case ALLOW_MEDIUM_REMOVAL: - case ERASE: - case REZERO_UNIT: - case SEEK_10: - case SPACE: - case START_STOP: - case TEST_UNIT_READY: - case VERIFY: - case WRITE_FILEMARKS: - ret = target_emulate_noop(task); - break; - default: - pr_err("Unsupported SCSI Opcode: 0x%02x for %s\n", - cmd->t_task_cdb[0], dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - } - - if (ret < 0) - return ret; - return PYX_TRANSPORT_SENT_TO_TRANSPORT; -} - /* * Write a CDB into @cdb that is based on the one the intiator sent us, * but updated to only cover the sectors that the current task handles. diff --git a/drivers/target/target_core_cdb.h b/drivers/target/target_core_cdb.h new file mode 100644 index 000000000000..ad6b1e393001 --- /dev/null +++ b/drivers/target/target_core_cdb.h @@ -0,0 +1,14 @@ +#ifndef TARGET_CORE_CDB_H +#define TARGET_CORE_CDB_H + +int target_emulate_inquiry(struct se_task *task); +int target_emulate_readcapacity(struct se_task *task); +int target_emulate_readcapacity_16(struct se_task *task); +int target_emulate_modesense(struct se_task *task); +int target_emulate_request_sense(struct se_task *task); +int target_emulate_unmap(struct se_task *task); +int target_emulate_write_same(struct se_task *task); +int target_emulate_synchronize_cache(struct se_task *task); +int target_emulate_noop(struct se_task *task); + +#endif /* TARGET_CORE_CDB_H */ diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 74015793c03a..f603b12485bd 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -52,6 +52,7 @@ #include #include "target_core_alua.h" +#include "target_core_cdb.h" #include "target_core_hba.h" #include "target_core_pr.h" #include "target_core_ua.h" @@ -2155,31 +2156,11 @@ static int __transport_execute_tasks(struct se_device *dev) atomic_set(&cmd->t_transport_sent, 1); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - /* - * The struct se_cmd->execute_task() function pointer is used - * to grab REPORT_LUNS and other CDBs we want to handle before they hit the - * struct se_subsystem_api->do_task() caller below. - */ - if (cmd->execute_task) { - error = cmd->execute_task(task); - } else { - /* - * Currently for all virtual TCM plugins including IBLOCK, FILEIO and - * RAMDISK we use the internal transport_emulate_control_cdb() logic - * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK - * LUN emulation code. - * - * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we - * call ->do_task() directly and let the underlying TCM subsystem plugin - * code handle the CDB emulation. - */ - if ((dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) && - (!(task->task_se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) - error = transport_emulate_control_cdb(task); - else - error = dev->transport->do_task(task); - } + if (cmd->execute_task) + error = cmd->execute_task(task); + else + error = dev->transport->do_task(task); if (error != 0) { cmd->transport_error_status = error; spin_lock_irqsave(&cmd->t_state_lock, flags); @@ -2622,6 +2603,13 @@ static int transport_generic_cmd_sequencer( */ } + /* + * If we operate in passthrough mode we skip most CDB emulation and + * instead hand the commands down to the physical SCSI device. + */ + passthrough = + (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV); + switch (cdb[0]) { case READ_6: sectors = transport_get_sectors_6(cdb, cmd, §or_ret); @@ -2701,9 +2689,12 @@ static int transport_generic_cmd_sequencer( cmd->t_task_lba = transport_lba_32(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; - if (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV) + /* + * Do now allow BIDI commands for passthrough mode. + */ + if (passthrough) goto out_unsupported_cdb; + /* * Setup BIDI XOR callback to be run after I/O completion. */ @@ -2712,13 +2703,6 @@ static int transport_generic_cmd_sequencer( break; case VARIABLE_LENGTH_CMD: service_action = get_unaligned_be16(&cdb[8]); - /* - * Determine if this is TCM/PSCSI device and we should disable - * internal emulation for this CDB. - */ - passthrough = (dev->transport->transport_type == - TRANSPORT_PLUGIN_PHBA_PDEV); - switch (service_action) { case XDWRITEREAD_32: sectors = transport_get_sectors_32(cdb, cmd, §or_ret); @@ -2732,8 +2716,12 @@ static int transport_generic_cmd_sequencer( cmd->t_task_lba = transport_lba_64_ext(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + /* + * Do now allow BIDI commands for passthrough mode. + */ if (passthrough) goto out_unsupported_cdb; + /* * Setup BIDI XOR callback to be run during after I/O * completion. @@ -2759,7 +2747,8 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[10], dev) < 0) goto out_invalid_cdb_field; - + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; default: pr_err("VARIABLE_LENGTH_CMD service action" @@ -2797,8 +2786,15 @@ static int transport_generic_cmd_sequencer( case MODE_SENSE: size = cdb[4]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_modesense; break; case MODE_SENSE_10: + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_modesense; + break; case GPCMD_READ_BUFFER_CAPACITY: case GPCMD_SEND_OPC: case LOG_SELECT: @@ -2867,6 +2863,8 @@ static int transport_generic_cmd_sequencer( if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) cmd->sam_task_attr = MSG_HEAD_TAG; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_inquiry; break; case READ_BUFFER: size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; @@ -2875,6 +2873,8 @@ static int transport_generic_cmd_sequencer( case READ_CAPACITY: size = READ_CAP_LEN; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_readcapacity; break; case READ_MEDIA_SERIAL_NUMBER: case SECURITY_PROTOCOL_IN: @@ -2883,6 +2883,21 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case SERVICE_ACTION_IN: + switch (cmd->t_task_cdb[1] & 0x1f) { + case SAI_READ_CAPACITY_16: + if (!passthrough) + cmd->execute_task = + target_emulate_readcapacity_16; + break; + default: + if (passthrough) + break; + + pr_err("Unsupported SA: 0x%02x\n", + cmd->t_task_cdb[1] & 0x1f); + goto out_unsupported_cdb; + } + /*FALLTHROUGH*/ case ACCESS_CONTROL_IN: case ACCESS_CONTROL_OUT: case EXTENDED_COPY: @@ -2913,6 +2928,8 @@ static int transport_generic_cmd_sequencer( case REQUEST_SENSE: size = cdb[4]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_request_sense; break; case READ_ELEMENT_STATUS: size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; @@ -2977,8 +2994,9 @@ static int transport_generic_cmd_sequencer( size = transport_get_size(sectors, cdb, cmd); cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (passthrough) break; + /* * Check to ensure that LBA + Range does not exceed past end of * device for IBLOCK and FILEIO ->do_sync_cache() backend calls @@ -2987,10 +3005,13 @@ static int transport_generic_cmd_sequencer( if (transport_cmd_get_valid_sectors(cmd) < 0) goto out_invalid_cdb_field; } + cmd->execute_task = target_emulate_synchronize_cache; break; case UNMAP: size = get_unaligned_be16(&cdb[7]); cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_unmap; break; case WRITE_SAME_16: sectors = transport_get_sectors_16(cdb, cmd, §or_ret); @@ -3009,6 +3030,8 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_invalid_cdb_field; + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; case WRITE_SAME: sectors = transport_get_sectors_10(cdb, cmd, §or_ret); @@ -3030,20 +3053,26 @@ static int transport_generic_cmd_sequencer( */ if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_invalid_cdb_field; + if (!passthrough) + cmd->execute_task = target_emulate_write_same; break; case ALLOW_MEDIUM_REMOVAL: - case GPCMD_CLOSE_TRACK: case ERASE: - case INITIALIZE_ELEMENT_STATUS: - case GPCMD_LOAD_UNLOAD: case REZERO_UNIT: case SEEK_10: - case GPCMD_SET_SPEED: case SPACE: case START_STOP: case TEST_UNIT_READY: case VERIFY: case WRITE_FILEMARKS: + cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; + if (!passthrough) + cmd->execute_task = target_emulate_noop; + break; + case GPCMD_CLOSE_TRACK: + case INITIALIZE_ELEMENT_STATUS: + case GPCMD_LOAD_UNLOAD: + case GPCMD_SET_SPEED: case MOVE_MEDIUM: cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; @@ -3100,6 +3129,11 @@ static int transport_generic_cmd_sequencer( cmd->data_length = size; } + /* reject any command that we don't have a handler for */ + if (!(passthrough || cmd->execute_task || + (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) + goto out_unsupported_cdb; + /* Let's limit control cdbs to a page, for simplicity's sake. */ if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && size > PAGE_SIZE) From 746cdfbf01c0a30d59f6e1b6942d432658d7c7cd Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 4 Nov 2011 12:00:45 +0100 Subject: [PATCH 1398/1596] hwmon: Avoid building drivers for powerpc that read/write ISA addresses A modprobe of hwmon drivers that read/write ISA addresses on a powerpc results in a kernel Oops. These reads/writes are being done via the inb()/in_8() and outb()/out_8() macros. Prevent these drivers from being built for powerpc. Signed-off-by: Dean Nelson Signed-off-by: Jean Delvare --- drivers/hwmon/Kconfig | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 9b347acf1559..279a509dca9f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -335,6 +335,7 @@ config SENSORS_I5K_AMB config SENSORS_F71805F tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG" + depends on !PPC help If you say yes here you get support for hardware monitoring features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG @@ -345,6 +346,7 @@ config SENSORS_F71805F config SENSORS_F71882FG tristate "Fintek F71882FG and compatibles" + depends on !PPC help If you say yes here you get support for hardware monitoring features of many Fintek Super-I/O (LPC) chips. The currently @@ -468,6 +470,7 @@ config SENSORS_IBMPEX config SENSORS_IT87 tristate "ITE IT87xx and compatibles" + depends on !PPC select HWMON_VID help If you say yes here you get support for ITE IT8705F, IT8712F, @@ -824,6 +827,7 @@ config SENSORS_NTC_THERMISTOR config SENSORS_PC87360 tristate "National Semiconductor PC87360 family" + depends on !PPC select HWMON_VID help If you say yes here you get access to the hardware monitoring @@ -837,6 +841,7 @@ config SENSORS_PC87360 config SENSORS_PC87427 tristate "National Semiconductor PC87427" + depends on !PPC help If you say yes here you get access to the hardware monitoring functions of the National Semiconductor PC87427 Super-I/O chip. @@ -928,7 +933,7 @@ config SENSORS_SMM665 config SENSORS_DME1737 tristate "SMSC DME1737, SCH311x and compatibles" - depends on I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL && !PPC select HWMON_VID help If you say yes here you get support for the hardware monitoring @@ -970,6 +975,7 @@ config SENSORS_EMC6W201 config SENSORS_SMSC47M1 tristate "SMSC LPC47M10x and compatibles" + depends on !PPC help If you say yes here you get support for the integrated fan monitoring and control capabilities of the SMSC LPC47B27x, @@ -1003,7 +1009,7 @@ config SENSORS_SMSC47M192 config SENSORS_SMSC47B397 tristate "SMSC LPC47B397-NC" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && !PPC help If you say yes here you get support for the SMSC LPC47B397-NC sensor chip. @@ -1017,6 +1023,7 @@ config SENSORS_SCH56XX_COMMON config SENSORS_SCH5627 tristate "SMSC SCH5627" + depends on !PPC select SENSORS_SCH56XX_COMMON help If you say yes here you get support for the hardware monitoring @@ -1027,6 +1034,7 @@ config SENSORS_SCH5627 config SENSORS_SCH5636 tristate "SMSC SCH5636" + depends on !PPC select SENSORS_SCH56XX_COMMON help SMSC SCH5636 Super I/O chips include an embedded microcontroller for @@ -1150,6 +1158,7 @@ config SENSORS_VIA686A config SENSORS_VT1211 tristate "VIA VT1211" + depends on !PPC select HWMON_VID help If you say yes here then you get support for hardware monitoring @@ -1262,6 +1271,7 @@ config SENSORS_W83L786NG config SENSORS_W83627HF tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF" + depends on !PPC select HWMON_VID help If you say yes here you get support for the Winbond W836X7 series @@ -1273,6 +1283,7 @@ config SENSORS_W83627HF config SENSORS_W83627EHF tristate "Winbond W83627EHF/EHG/DHG, W83667HG, NCT6775F, NCT6776F" + depends on !PPC select HWMON_VID help If you say yes here you get support for the hardware From 24d6e2a89a1ff0a035f163a83a2812a3192083b6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:46 +0100 Subject: [PATCH 1399/1596] hwmon: (lm73) Make detection less problematic Word reads can cause trouble with some I2C devices, so do as much detection as we can using only byte reads, and only use a word read in the end to confirm the positive match. Also properly handle read errors. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck Cc: Robert Casanova --- drivers/hwmon/lm73.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 29b9030d42c3..24be17608fbb 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -150,17 +150,31 @@ static int lm73_detect(struct i2c_client *new_client, struct i2c_board_info *info) { struct i2c_adapter *adapter = new_client->adapter; - u16 id; - u8 ctrl; + int id, ctrl, conf; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; + /* + * Do as much detection as possible with byte reads first, as word + * reads can confuse other devices. + */ + ctrl = i2c_smbus_read_byte_data(new_client, LM73_REG_CTRL); + if (ctrl < 0 || (ctrl & 0x10)) + return -ENODEV; + + conf = i2c_smbus_read_byte_data(new_client, LM73_REG_CONF); + if (conf < 0 || (conf & 0x0c)) + return -ENODEV; + + id = i2c_smbus_read_byte_data(new_client, LM73_REG_ID); + if (id < 0 || id != (LM73_ID & 0xff)) + return -ENODEV; + /* Check device ID */ id = i2c_smbus_read_word_data(new_client, LM73_REG_ID); - ctrl = i2c_smbus_read_byte_data(new_client, LM73_REG_CTRL); - if ((id != LM73_ID) || (ctrl & 0x10)) + if (id < 0 || id != LM73_ID) return -ENODEV; strlcpy(info->type, "lm73", I2C_NAME_SIZE); From 547a1c99d0052c8bee0a8fe4091e6a9094c3cde3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:46 +0100 Subject: [PATCH 1400/1596] hwmon: (ibmaem) Fix error paths I am under the impression that error paths in functions aem_init_aem1_inst() and aem_init_aem2_inst() are incorrect. In several cases, the function returns 0 on error, which I suspect is not intended. Fix this by properly tracking error codes. Signed-off-by: Jean Delvare Acked-by: Darrick J. Wong Acked-by: Guenter Roeck --- drivers/hwmon/ibmaem.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index 783d0c17b762..aba6b59dc3a5 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -570,24 +570,26 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) platform_set_drvdata(data->pdev, data); /* Set up IPMI interface */ - if (aem_init_ipmi_data(&data->ipmi, probe->interface, - probe->bmc_device)) + res = aem_init_ipmi_data(&data->ipmi, probe->interface, + probe->bmc_device); + if (res) goto ipmi_err; /* Register with hwmon */ data->hwmon_dev = hwmon_device_register(&data->pdev->dev); - if (IS_ERR(data->hwmon_dev)) { dev_err(&data->pdev->dev, "Unable to register hwmon " "device for IPMI interface %d\n", probe->interface); + res = PTR_ERR(data->hwmon_dev); goto hwmon_reg_err; } data->update = update_aem1_sensors; /* Find sensors */ - if (aem1_find_sensors(data)) + res = aem1_find_sensors(data); + if (res) goto sensor_err; /* Add to our list of AEM devices */ @@ -704,24 +706,26 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, platform_set_drvdata(data->pdev, data); /* Set up IPMI interface */ - if (aem_init_ipmi_data(&data->ipmi, probe->interface, - probe->bmc_device)) + res = aem_init_ipmi_data(&data->ipmi, probe->interface, + probe->bmc_device); + if (res) goto ipmi_err; /* Register with hwmon */ data->hwmon_dev = hwmon_device_register(&data->pdev->dev); - if (IS_ERR(data->hwmon_dev)) { dev_err(&data->pdev->dev, "Unable to register hwmon " "device for IPMI interface %d\n", probe->interface); + res = PTR_ERR(data->hwmon_dev); goto hwmon_reg_err; } data->update = update_aem2_sensors; /* Find sensors */ - if (aem2_find_sensors(data)) + res = aem2_find_sensors(data); + if (res) goto sensor_err; /* Add to our list of AEM devices */ From 9d84c9e8b5b0386ee1d7769de0ff8a2546a2d054 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:46 +0100 Subject: [PATCH 1401/1596] hwmon: (ibmaem) Make instance initializations independent There is no good reason that I can see why the failure to initialize one instance should prevent other instances from being initialized. Signed-off-by: Jean Delvare Acked-by: Darrick J. Wong Acked-by: Guenter Roeck --- drivers/hwmon/ibmaem.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index aba6b59dc3a5..1fed86b307f5 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -245,8 +245,6 @@ static void aem_bmc_gone(int iface); static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static void aem_remove_sensors(struct aem_data *data); -static int aem_init_aem1(struct aem_ipmi_data *probe); -static int aem_init_aem2(struct aem_ipmi_data *probe); static int aem1_find_sensors(struct aem_data *data); static int aem2_find_sensors(struct aem_data *data); static void update_aem1_sensors(struct aem_data *data); @@ -616,7 +614,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) } /* Find and initialize all AEM1 instances */ -static int aem_init_aem1(struct aem_ipmi_data *probe) +static void aem_init_aem1(struct aem_ipmi_data *probe) { int num, i, err; @@ -627,11 +625,8 @@ static int aem_init_aem1(struct aem_ipmi_data *probe) dev_err(probe->bmc_device, "Error %d initializing AEM1 0x%X\n", err, i); - return err; } } - - return 0; } /* Probe functions for AEM2 devices */ @@ -752,7 +747,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, } /* Find and initialize all AEM2 instances */ -static int aem_init_aem2(struct aem_ipmi_data *probe) +static void aem_init_aem2(struct aem_ipmi_data *probe) { struct aem_find_instance_resp fi_resp; int err; @@ -771,12 +766,9 @@ static int aem_init_aem2(struct aem_ipmi_data *probe) dev_err(probe->bmc_device, "Error %d initializing AEM2 0x%X\n", err, fi_resp.module_handle); - return err; } i++; } - - return 0; } /* Probe a BMC for AEM firmware instances */ From da8ebe4e09ee5661f125a8401ade58baf226aa57 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:46 +0100 Subject: [PATCH 1402/1596] hwmon: (ibmaem) Avoid repeated memory allocations Preallocate a buffer for the response to sensor reads, and reuse it for each read instead of allocating a new one each time. This should be faster and should also avoid memory fragmentation. Signed-off-by: Jean Delvare Acked-by: Darrick J. Wong Acked-by: Guenter Roeck --- drivers/hwmon/ibmaem.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index 1fed86b307f5..6a967d7dbdee 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -147,8 +147,9 @@ struct aem_data { int id; struct aem_ipmi_data ipmi; - /* Function to update sensors */ + /* Function and buffer to update sensors */ void (*update)(struct aem_data *data); + struct aem_read_sensor_resp *rs_resp; /* * AEM 1.x sensors: @@ -355,13 +356,14 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) /* Sensor support functions */ -/* Read a sensor value */ +/* Read a sensor value; must be called with data->lock held */ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, void *buf, size_t size) { int rs_size, res; struct aem_read_sensor_req rs_req; - struct aem_read_sensor_resp *rs_resp; + /* Use preallocated rx buffer */ + struct aem_read_sensor_resp *rs_resp = data->rs_resp; struct aem_ipmi_data *ipmi = &data->ipmi; /* AEM registers are 1, 2, 4 or 8 bytes */ @@ -387,10 +389,6 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, ipmi->tx_message.data_len = sizeof(rs_req); rs_size = sizeof(*rs_resp) + size; - rs_resp = kzalloc(rs_size, GFP_KERNEL); - if (!rs_resp) - return -ENOMEM; - ipmi->rx_msg_data = rs_resp; ipmi->rx_msg_len = rs_size; @@ -433,7 +431,6 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, res = 0; out: - kfree(rs_resp); return res; } @@ -491,6 +488,7 @@ static void aem_delete(struct aem_data *data) { list_del(&data->list); aem_remove_sensors(data); + kfree(data->rs_resp); hwmon_device_unregister(data->hwmon_dev); ipmi_destroy_user(data->ipmi.user); platform_set_drvdata(data->pdev, NULL); @@ -584,6 +582,11 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) } data->update = update_aem1_sensors; + data->rs_resp = kzalloc(sizeof(*(data->rs_resp)) + 8, GFP_KERNEL); + if (!data->rs_resp) { + res = -ENOMEM; + goto alloc_resp_err; + } /* Find sensors */ res = aem1_find_sensors(data); @@ -599,6 +602,8 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) return 0; sensor_err: + kfree(data->rs_resp); +alloc_resp_err: hwmon_device_unregister(data->hwmon_dev); hwmon_reg_err: ipmi_destroy_user(data->ipmi.user); @@ -717,6 +722,11 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, } data->update = update_aem2_sensors; + data->rs_resp = kzalloc(sizeof(*(data->rs_resp)) + 8, GFP_KERNEL); + if (!data->rs_resp) { + res = -ENOMEM; + goto alloc_resp_err; + } /* Find sensors */ res = aem2_find_sensors(data); @@ -732,6 +742,8 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, return 0; sensor_err: + kfree(data->rs_resp); +alloc_resp_err: hwmon_device_unregister(data->hwmon_dev); hwmon_reg_err: ipmi_destroy_user(data->ipmi.user); From 8dc089d68b125179b1c97e75d29623472d99c68b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:46 +0100 Subject: [PATCH 1403/1596] hwmon: (lm90) Fix warnings With some configuration option combinations, we get the following warnings: drivers/hwmon/lm90.c: In function 'lm90_detect': drivers/hwmon/lm90.c:1114: warning: 'chip_id' may be used uninitialized in this function drivers/hwmon/lm90.c:1114: warning: 'reg_config1' may be used uninitialized in this function drivers/hwmon/lm90.c:1114: warning: 'reg_convrate' may be used uninitialized in this function drivers/hwmon/lm90.c:1187: warning: 'reg_emerg2' may be used uninitialized in this function drivers/hwmon/lm90.c:1187: warning: 'reg_status2' may be used uninitialized in this function We can solve these easily by reading the register values first and checking for errors later. These errors should be very rare, even in the case of failed detection, so this change has no impact on performance. And this makes checkpatch.pl happier. Reported-by: Guenter Roeck Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/lm90.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 90ddb8774210..60b3e3030277 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1117,14 +1117,12 @@ static int lm90_detect(struct i2c_client *new_client, return -ENODEV; /* detection and identification */ - if ((man_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_MAN_ID)) < 0 - || (chip_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CHIP_ID)) < 0 - || (reg_config1 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG1)) < 0 - || (reg_convrate = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONVRATE)) < 0) + man_id = i2c_smbus_read_byte_data(new_client, LM90_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CHIP_ID); + reg_config1 = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CONFIG1); + reg_convrate = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONVRATE); + if (man_id < 0 || chip_id < 0 || reg_config1 < 0 || reg_convrate < 0) return -ENODEV; if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) { @@ -1192,13 +1190,16 @@ static int lm90_detect(struct i2c_client *new_client, * exists, both readings will reflect the same value. Otherwise, * the readings will be different. */ - if ((reg_emerg = i2c_smbus_read_byte_data(new_client, - MAX6659_REG_R_REMOTE_EMERG)) < 0 - || i2c_smbus_read_byte_data(new_client, LM90_REG_R_MAN_ID) < 0 - || (reg_emerg2 = i2c_smbus_read_byte_data(new_client, - MAX6659_REG_R_REMOTE_EMERG)) < 0 - || (reg_status2 = i2c_smbus_read_byte_data(new_client, - MAX6696_REG_R_STATUS2)) < 0) + reg_emerg = i2c_smbus_read_byte_data(new_client, + MAX6659_REG_R_REMOTE_EMERG); + man_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_MAN_ID); + reg_emerg2 = i2c_smbus_read_byte_data(new_client, + MAX6659_REG_R_REMOTE_EMERG); + reg_status2 = i2c_smbus_read_byte_data(new_client, + MAX6696_REG_R_STATUS2); + if (reg_emerg < 0 || man_id < 0 || reg_emerg2 < 0 + || reg_status2 < 0) return -ENODEV; /* From b2589ab02b46ea4a80b30a90fc2fe8eed957e86a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:47 +0100 Subject: [PATCH 1404/1596] hwmon: (lm90) Make code more readable Clean up the code to make it more readable: * Remove reg_ and new_ prefixes from variable names, they made the names longer, causing extra line breaks, while not adding much value. * Introduce struct device dev* = &client->dev in two functions, to avoid repeating client->dev everywhere in these functions. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/lm90.c | 143 +++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 74 deletions(-) diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 60b3e3030277..615bc4f4e530 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1105,39 +1105,37 @@ static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec); */ /* Return 0 if detection is successful, -ENODEV otherwise */ -static int lm90_detect(struct i2c_client *new_client, +static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info) { - struct i2c_adapter *adapter = new_client->adapter; - int address = new_client->addr; + struct i2c_adapter *adapter = client->adapter; + int address = client->addr; const char *name = NULL; - int man_id, chip_id, reg_config1, reg_config2, reg_convrate; + int man_id, chip_id, config1, config2, convrate; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; /* detection and identification */ - man_id = i2c_smbus_read_byte_data(new_client, LM90_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CONFIG1); - reg_convrate = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONVRATE); - if (man_id < 0 || chip_id < 0 || reg_config1 < 0 || reg_convrate < 0) + man_id = i2c_smbus_read_byte_data(client, LM90_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(client, LM90_REG_R_CHIP_ID); + config1 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); + convrate = i2c_smbus_read_byte_data(client, LM90_REG_R_CONVRATE); + if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0) return -ENODEV; if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) { - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG2); - if (reg_config2 < 0) + config2 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG2); + if (config2 < 0) return -ENODEV; } else - reg_config2 = 0; /* Make compiler happy */ + config2 = 0; /* Make compiler happy */ if ((address == 0x4C || address == 0x4D) && man_id == 0x01) { /* National Semiconductor */ - if ((reg_config1 & 0x2A) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && reg_convrate <= 0x09) { + if ((config1 & 0x2A) == 0x00 + && (config2 & 0xF8) == 0x00 + && convrate <= 0x09) { if (address == 0x4C && (chip_id & 0xF0) == 0x20) { /* LM90 */ name = "lm90"; @@ -1161,8 +1159,8 @@ static int lm90_detect(struct i2c_client *new_client, if ((address == 0x4C || address == 0x4D) && man_id == 0x41) { /* Analog Devices */ if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ - && (reg_config1 & 0x3F) == 0x00 - && reg_convrate <= 0x0A) { + && (config1 & 0x3F) == 0x00 + && convrate <= 0x0A) { name = "adm1032"; /* The ADM1032 supports PEC, but only if combined transactions are not used. */ @@ -1171,18 +1169,18 @@ static int lm90_detect(struct i2c_client *new_client, info->flags |= I2C_CLIENT_PEC; } else if (chip_id == 0x51 /* ADT7461 */ - && (reg_config1 & 0x1B) == 0x00 - && reg_convrate <= 0x0A) { + && (config1 & 0x1B) == 0x00 + && convrate <= 0x0A) { name = "adt7461"; } else if (chip_id == 0x57 /* ADT7461A, NCT1008 */ - && (reg_config1 & 0x1B) == 0x00 - && reg_convrate <= 0x0A) { + && (config1 & 0x1B) == 0x00 + && convrate <= 0x0A) { name = "adt7461a"; } } else if (man_id == 0x4D) { /* Maxim */ - int reg_emerg, reg_emerg2, reg_status2; + int emerg, emerg2, status2; /* * We read MAX6659_REG_R_REMOTE_EMERG twice, and re-read @@ -1190,16 +1188,15 @@ static int lm90_detect(struct i2c_client *new_client, * exists, both readings will reflect the same value. Otherwise, * the readings will be different. */ - reg_emerg = i2c_smbus_read_byte_data(new_client, - MAX6659_REG_R_REMOTE_EMERG); - man_id = i2c_smbus_read_byte_data(new_client, + emerg = i2c_smbus_read_byte_data(client, + MAX6659_REG_R_REMOTE_EMERG); + man_id = i2c_smbus_read_byte_data(client, LM90_REG_R_MAN_ID); - reg_emerg2 = i2c_smbus_read_byte_data(new_client, + emerg2 = i2c_smbus_read_byte_data(client, MAX6659_REG_R_REMOTE_EMERG); - reg_status2 = i2c_smbus_read_byte_data(new_client, - MAX6696_REG_R_STATUS2); - if (reg_emerg < 0 || man_id < 0 || reg_emerg2 < 0 - || reg_status2 < 0) + status2 = i2c_smbus_read_byte_data(client, + MAX6696_REG_R_STATUS2); + if (emerg < 0 || man_id < 0 || emerg2 < 0 || status2 < 0) return -ENODEV; /* @@ -1217,8 +1214,8 @@ static int lm90_detect(struct i2c_client *new_client, */ if (chip_id == man_id && (address == 0x4C || address == 0x4D || address == 0x4E) - && (reg_config1 & 0x1F) == (man_id & 0x0F) - && reg_convrate <= 0x09) { + && (config1 & 0x1F) == (man_id & 0x0F) + && convrate <= 0x09) { if (address == 0x4C) name = "max6657"; else @@ -1236,10 +1233,10 @@ static int lm90_detect(struct i2c_client *new_client, * one of those registers exists. */ if (chip_id == 0x01 - && (reg_config1 & 0x10) == 0x00 - && (reg_status2 & 0x01) == 0x00 - && reg_emerg == reg_emerg2 - && reg_convrate <= 0x07) { + && (config1 & 0x10) == 0x00 + && (status2 & 0x01) == 0x00 + && emerg == emerg2 + && convrate <= 0x07) { name = "max6696"; } else /* @@ -1249,8 +1246,8 @@ static int lm90_detect(struct i2c_client *new_client, * second to last bit of config1 (software reset). */ if (chip_id == 0x01 - && (reg_config1 & 0x03) == 0x00 - && reg_convrate <= 0x07) { + && (config1 & 0x03) == 0x00 + && convrate <= 0x07) { name = "max6680"; } else /* @@ -1259,21 +1256,21 @@ static int lm90_detect(struct i2c_client *new_client, * register are unused and should return zero when read. */ if (chip_id == 0x59 - && (reg_config1 & 0x3f) == 0x00 - && reg_convrate <= 0x07) { + && (config1 & 0x3f) == 0x00 + && convrate <= 0x07) { name = "max6646"; } } else if (address == 0x4C && man_id == 0x5C) { /* Winbond/Nuvoton */ - if ((reg_config1 & 0x2A) == 0x00 - && (reg_config2 & 0xF8) == 0x00) { + if ((config1 & 0x2A) == 0x00 + && (config2 & 0xF8) == 0x00) { if (chip_id == 0x01 /* W83L771W/G */ - && reg_convrate <= 0x09) { + && convrate <= 0x09) { name = "w83l771"; } else if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */ - && reg_convrate <= 0x08) { + && convrate <= 0x08) { name = "w83l771"; } } @@ -1281,9 +1278,9 @@ static int lm90_detect(struct i2c_client *new_client, if (address >= 0x48 && address <= 0x4F && man_id == 0xA1) { /* NXP Semiconductor/Philips */ if (chip_id == 0x00 - && (reg_config1 & 0x2A) == 0x00 - && (reg_config2 & 0xFE) == 0x00 - && reg_convrate <= 0x09) { + && (config1 & 0x2A) == 0x00 + && (config2 & 0xFE) == 0x00 + && convrate <= 0x09) { name = "sa56004"; } } @@ -1302,19 +1299,18 @@ static int lm90_detect(struct i2c_client *new_client, static void lm90_remove_files(struct i2c_client *client, struct lm90_data *data) { + struct device *dev = &client->dev; + if (data->flags & LM90_HAVE_TEMP3) - sysfs_remove_group(&client->dev.kobj, &lm90_temp3_group); + sysfs_remove_group(&dev->kobj, &lm90_temp3_group); if (data->flags & LM90_HAVE_EMERGENCY_ALARM) - sysfs_remove_group(&client->dev.kobj, - &lm90_emergency_alarm_group); + sysfs_remove_group(&dev->kobj, &lm90_emergency_alarm_group); if (data->flags & LM90_HAVE_EMERGENCY) - sysfs_remove_group(&client->dev.kobj, - &lm90_emergency_group); + sysfs_remove_group(&dev->kobj, &lm90_emergency_group); if (data->flags & LM90_HAVE_OFFSET) - device_remove_file(&client->dev, - &sensor_dev_attr_temp2_offset.dev_attr); - device_remove_file(&client->dev, &dev_attr_pec); - sysfs_remove_group(&client->dev.kobj, &lm90_group); + device_remove_file(dev, &sensor_dev_attr_temp2_offset.dev_attr); + device_remove_file(dev, &dev_attr_pec); + sysfs_remove_group(&dev->kobj, &lm90_group); } static void lm90_init_client(struct i2c_client *client) @@ -1363,10 +1359,11 @@ static void lm90_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); } -static int lm90_probe(struct i2c_client *new_client, +static int lm90_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct i2c_adapter *adapter = to_i2c_adapter(new_client->dev.parent); + struct device *dev = &client->dev; + struct i2c_adapter *adapter = to_i2c_adapter(dev->parent); struct lm90_data *data; int err; @@ -1375,14 +1372,14 @@ static int lm90_probe(struct i2c_client *new_client, err = -ENOMEM; goto exit; } - i2c_set_clientdata(new_client, data); + i2c_set_clientdata(client, data); mutex_init(&data->update_lock); /* Set the device type */ data->kind = id->driver_data; if (data->kind == adm1032) { if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - new_client->flags &= ~I2C_CLIENT_PEC; + client->flags &= ~I2C_CLIENT_PEC; } /* Different devices have different alarm bits triggering the @@ -1397,43 +1394,41 @@ static int lm90_probe(struct i2c_client *new_client, data->max_convrate = lm90_params[data->kind].max_convrate; /* Initialize the LM90 chip */ - lm90_init_client(new_client); + lm90_init_client(client); /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &lm90_group); + err = sysfs_create_group(&dev->kobj, &lm90_group); if (err) goto exit_free; - if (new_client->flags & I2C_CLIENT_PEC) { - err = device_create_file(&new_client->dev, &dev_attr_pec); + if (client->flags & I2C_CLIENT_PEC) { + err = device_create_file(dev, &dev_attr_pec); if (err) goto exit_remove_files; } if (data->flags & LM90_HAVE_OFFSET) { - err = device_create_file(&new_client->dev, + err = device_create_file(dev, &sensor_dev_attr_temp2_offset.dev_attr); if (err) goto exit_remove_files; } if (data->flags & LM90_HAVE_EMERGENCY) { - err = sysfs_create_group(&new_client->dev.kobj, - &lm90_emergency_group); + err = sysfs_create_group(&dev->kobj, &lm90_emergency_group); if (err) goto exit_remove_files; } if (data->flags & LM90_HAVE_EMERGENCY_ALARM) { - err = sysfs_create_group(&new_client->dev.kobj, + err = sysfs_create_group(&dev->kobj, &lm90_emergency_alarm_group); if (err) goto exit_remove_files; } if (data->flags & LM90_HAVE_TEMP3) { - err = sysfs_create_group(&new_client->dev.kobj, - &lm90_temp3_group); + err = sysfs_create_group(&dev->kobj, &lm90_temp3_group); if (err) goto exit_remove_files; } - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; @@ -1442,7 +1437,7 @@ static int lm90_probe(struct i2c_client *new_client, return 0; exit_remove_files: - lm90_remove_files(new_client, data); + lm90_remove_files(client, data); exit_free: kfree(data); exit: From 371f2e083b9b081adf68d04fba4978a27dc4e618 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:47 +0100 Subject: [PATCH 1405/1596] hwmon: (smsc47b397) Fix checkpatch errors Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/smsc47b397.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 9fb7516e6f45..65c88ff5645a 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -113,7 +113,7 @@ struct smsc47b397_data { u8 temp[4]; }; -static int smsc47b397_read_value(struct smsc47b397_data* data, u8 reg) +static int smsc47b397_read_value(struct smsc47b397_data *data, u8 reg) { int res; @@ -265,7 +265,8 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev) return -EBUSY; } - if (!(data = kzalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct smsc47b397_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto error_release; } @@ -276,7 +277,8 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev) mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); - if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group))) + err = sysfs_create_group(&dev->kobj, &smsc47b397_group); + if (err) goto error_free; data->hwmon_dev = hwmon_device_register(dev); @@ -345,7 +347,7 @@ static int __init smsc47b397_find(unsigned short *addr) superio_enter(); id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID); - switch(id) { + switch (id) { case 0x81: name = "SCH5307-NS"; break; @@ -379,7 +381,8 @@ static int __init smsc47b397_init(void) unsigned short address; int ret; - if ((ret = smsc47b397_find(&address))) + ret = smsc47b397_find(&address); + if (ret) return ret; ret = platform_driver_register(&smsc47b397_driver); From 90f4102ce59226954edbe960b2434d8b3da5f086 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:47 +0100 Subject: [PATCH 1406/1596] hwmon: Use i2c_smbus_{read,write}_word_swapped Make use of the new i2c_smbus_{read,write}_word_swapped functions. This makes the driver code more compact and readable. It also ensures proper error handling. Signed-off-by: Jean Delvare Acked-by: Jonathan Cameron Acked-by: Guenter Roeck Cc: Dirk Eibach Cc: "Mark M. Hoffman" Cc: Guillaume Ligneul --- drivers/hwmon/ad7414.c | 7 +++--- drivers/hwmon/ad7418.c | 27 +++++++-------------- drivers/hwmon/ads1015.c | 21 ++++------------ drivers/hwmon/ads7828.c | 12 +++------- drivers/hwmon/asb100.c | 10 ++++---- drivers/hwmon/ds1621.c | 24 +++---------------- drivers/hwmon/ds620.c | 42 ++++++++------------------------ drivers/hwmon/gl518sm.c | 4 ++-- drivers/hwmon/gl520sm.c | 4 ++-- drivers/hwmon/jc42.c | 52 ++++++++++++++++------------------------ drivers/hwmon/lm73.c | 8 +++---- drivers/hwmon/lm75.c | 9 +++---- drivers/hwmon/lm77.c | 4 ++-- drivers/hwmon/lm92.c | 26 ++++++++++---------- drivers/hwmon/max16065.c | 4 ++-- drivers/hwmon/sht21.c | 26 ++++---------------- drivers/hwmon/smm665.c | 15 ++++-------- drivers/hwmon/tmp102.c | 44 +++++++++++++--------------------- drivers/hwmon/w83781d.c | 10 ++++---- 19 files changed, 115 insertions(+), 234 deletions(-) diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c index d46c0c758ddf..df29a7fff9e7 100644 --- a/drivers/hwmon/ad7414.c +++ b/drivers/hwmon/ad7414.c @@ -58,10 +58,9 @@ static inline int ad7414_temp_from_reg(s16 reg) static inline int ad7414_read(struct i2c_client *client, u8 reg) { - if (reg == AD7414_REG_TEMP) { - int value = i2c_smbus_read_word_data(client, reg); - return (value < 0) ? value : swab16(value); - } else + if (reg == AD7414_REG_TEMP) + return i2c_smbus_read_word_swapped(client, reg); + else return i2c_smbus_read_byte_data(client, reg); } diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index ffc781fec185..8cb718ce8237 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -76,20 +76,6 @@ static struct i2c_driver ad7418_driver = { .id_table = ad7418_id, }; -/* All registers are word-sized, except for the configuration registers. - * AD7418 uses a high-byte first convention. Do NOT use those functions to - * access the configuration registers CONF and CONF2, as they are byte-sized. - */ -static inline int ad7418_read(struct i2c_client *client, u8 reg) -{ - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -static inline int ad7418_write(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - static void ad7418_init_client(struct i2c_client *client) { struct ad7418_data *data = i2c_get_clientdata(client); @@ -128,7 +114,9 @@ static struct ad7418_data *ad7418_update_device(struct device *dev) udelay(30); for (i = 0; i < 3; i++) { - data->temp[i] = ad7418_read(client, AD7418_REG_TEMP[i]); + data->temp[i] = + i2c_smbus_read_word_swapped(client, + AD7418_REG_TEMP[i]); } for (i = 0, ch = 4; i < data->adc_max; i++, ch--) { @@ -138,11 +126,12 @@ static struct ad7418_data *ad7418_update_device(struct device *dev) udelay(15); data->in[data->adc_max - 1 - i] = - ad7418_read(client, AD7418_REG_ADC); + i2c_smbus_read_word_swapped(client, + AD7418_REG_ADC); } /* restore old configuration value */ - ad7418_write(client, AD7418_REG_CONF, cfg); + i2c_smbus_write_word_swapped(client, AD7418_REG_CONF, cfg); data->last_updated = jiffies; data->valid = 1; @@ -182,7 +171,9 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, mutex_lock(&data->lock); data->temp[attr->index] = LM75_TEMP_TO_REG(temp); - ad7418_write(client, AD7418_REG_TEMP[attr->index], data->temp[attr->index]); + i2c_smbus_write_word_swapped(client, + AD7418_REG_TEMP[attr->index], + data->temp[attr->index]); mutex_unlock(&data->lock); return count; } diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index e9beeda4cbe5..eedca3cf9968 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c @@ -59,19 +59,6 @@ struct ads1015_data { struct ads1015_channel_data channel_data[ADS1015_CHANNELS]; }; -static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg) -{ - s32 data = i2c_smbus_read_word_data(client, reg); - - return (data < 0) ? data : swab16(data); -} - -static s32 ads1015_write_reg(struct i2c_client *client, unsigned int reg, - u16 val) -{ - return i2c_smbus_write_word_data(client, reg, swab16(val)); -} - static int ads1015_read_value(struct i2c_client *client, unsigned int channel, int *value) { @@ -87,7 +74,7 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel, mutex_lock(&data->update_lock); /* get channel parameters */ - res = ads1015_read_reg(client, ADS1015_CONFIG); + res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG); if (res < 0) goto err_unlock; config = res; @@ -101,13 +88,13 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel, config |= (pga & 0x0007) << 9; config |= (data_rate & 0x0007) << 5; - res = ads1015_write_reg(client, ADS1015_CONFIG, config); + res = i2c_smbus_write_word_swapped(client, ADS1015_CONFIG, config); if (res < 0) goto err_unlock; /* wait until conversion finished */ msleep(conversion_time_ms); - res = ads1015_read_reg(client, ADS1015_CONFIG); + res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG); if (res < 0) goto err_unlock; config = res; @@ -117,7 +104,7 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel, goto err_unlock; } - res = ads1015_read_reg(client, ADS1015_CONVERSION); + res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION); if (res < 0) goto err_unlock; conversion = res; diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index c42c5a69a664..cfcc3b6fb6bf 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -74,13 +74,6 @@ static int ads7828_detect(struct i2c_client *client, static int ads7828_probe(struct i2c_client *client, const struct i2c_device_id *id); -/* The ADS7828 returns the 12-bit sample in two bytes, - these are read as a word then byte-swapped */ -static u16 ads7828_read_value(struct i2c_client *client, u8 reg) -{ - return swab16(i2c_smbus_read_word_data(client, reg)); -} - static inline u8 channel_cmd_byte(int ch) { /* cmd byte C2,C1,C0 - see datasheet */ @@ -104,7 +97,8 @@ static struct ads7828_data *ads7828_update_device(struct device *dev) for (ch = 0; ch < ADS7828_NCH; ch++) { u8 cmd = channel_cmd_byte(ch); - data->adc_input[ch] = ads7828_read_value(client, cmd); + data->adc_input[ch] = + i2c_smbus_read_word_swapped(client, cmd); } data->last_updated = jiffies; data->valid = 1; @@ -203,7 +197,7 @@ static int ads7828_detect(struct i2c_client *client, for (ch = 0; ch < ADS7828_NCH; ch++) { u16 in_data; u8 cmd = channel_cmd_byte(ch); - in_data = ads7828_read_value(client, cmd); + in_data = i2c_smbus_read_word_swapped(client, cmd); if (in_data & 0xF000) { pr_debug("%s : Doesn't look like an ads7828 device\n", __func__); diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index c02a052d3085..d7bd1f3f2a31 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -829,17 +829,17 @@ static int asb100_read_value(struct i2c_client *client, u16 reg) /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data(cl, 0)); + res = i2c_smbus_read_word_swapped(cl, 0); break; case 0x52: /* CONFIG */ res = i2c_smbus_read_byte_data(cl, 1); break; case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data(cl, 2)); + res = i2c_smbus_read_word_swapped(cl, 2); break; case 0x55: /* MAX */ default: - res = swab16(i2c_smbus_read_word_data(cl, 3)); + res = i2c_smbus_read_word_swapped(cl, 3); break; } } @@ -877,10 +877,10 @@ static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) i2c_smbus_write_byte_data(cl, 1, value & 0xff); break; case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); + i2c_smbus_write_word_swapped(cl, 2, value); break; case 0x55: /* MAX */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); + i2c_smbus_write_word_swapped(cl, 3, value); break; } } diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index e11363467a8d..ef1ac996752e 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -80,24 +80,6 @@ struct ds1621_data { u8 conf; /* Register encoding, combined */ }; -/* Temperature registers are word-sized. - DS1621 uses a high-byte first convention, which is exactly opposite to - the SMBus standard. */ -static int ds1621_read_temp(struct i2c_client *client, u8 reg) -{ - int ret; - - ret = i2c_smbus_read_word_data(client, reg); - if (ret < 0) - return ret; - return swab16(ret); -} - -static int ds1621_write_temp(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - static void ds1621_init_client(struct i2c_client *client) { u8 conf, new_conf; @@ -136,7 +118,7 @@ static struct ds1621_data *ds1621_update_client(struct device *dev) data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); for (i = 0; i < ARRAY_SIZE(data->temp); i++) - data->temp[i] = ds1621_read_temp(client, + data->temp[i] = i2c_smbus_read_word_swapped(client, DS1621_REG_TEMP[i]); /* reset alarms if necessary */ @@ -177,8 +159,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, mutex_lock(&data->update_lock); data->temp[attr->index] = val; - ds1621_write_temp(client, DS1621_REG_TEMP[attr->index], - data->temp[attr->index]); + i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index], + data->temp[attr->index]); mutex_unlock(&data->update_lock); return count; } diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index 4f7c3fc40a89..225ae4f36583 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c @@ -75,33 +75,13 @@ struct ds620_data { s16 temp[3]; /* Register values, word */ }; -/* - * Temperature registers are word-sized. - * DS620 uses a high-byte first convention, which is exactly opposite to - * the SMBus standard. - */ -static int ds620_read_temp(struct i2c_client *client, u8 reg) -{ - int ret; - - ret = i2c_smbus_read_word_data(client, reg); - if (ret < 0) - return ret; - return swab16(ret); -} - -static int ds620_write_temp(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - static void ds620_init_client(struct i2c_client *client) { struct ds620_platform_data *ds620_info = client->dev.platform_data; u16 conf, new_conf; new_conf = conf = - swab16(i2c_smbus_read_word_data(client, DS620_REG_CONF)); + i2c_smbus_read_word_swapped(client, DS620_REG_CONF); /* switch to continuous conversion mode */ new_conf &= ~DS620_REG_CONFIG_1SHOT; @@ -118,8 +98,7 @@ static void ds620_init_client(struct i2c_client *client) new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0; if (conf != new_conf) - i2c_smbus_write_word_data(client, DS620_REG_CONF, - swab16(new_conf)); + i2c_smbus_write_word_swapped(client, DS620_REG_CONF, new_conf); /* start conversion */ i2c_smbus_write_byte(client, DS620_COM_START); @@ -141,8 +120,8 @@ static struct ds620_data *ds620_update_client(struct device *dev) dev_dbg(&client->dev, "Starting ds620 update\n"); for (i = 0; i < ARRAY_SIZE(data->temp); i++) { - res = ds620_read_temp(client, - DS620_REG_TEMP[i]); + res = i2c_smbus_read_word_swapped(client, + DS620_REG_TEMP[i]); if (res < 0) { ret = ERR_PTR(res); goto abort; @@ -191,8 +170,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, mutex_lock(&data->update_lock); data->temp[attr->index] = val; - ds620_write_temp(client, DS620_REG_TEMP[attr->index], - data->temp[attr->index]); + i2c_smbus_write_word_swapped(client, DS620_REG_TEMP[attr->index], + data->temp[attr->index]); mutex_unlock(&data->update_lock); return count; } @@ -210,16 +189,15 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *da, return PTR_ERR(data); /* reset alarms if necessary */ - res = i2c_smbus_read_word_data(client, DS620_REG_CONF); + res = i2c_smbus_read_word_swapped(client, DS620_REG_CONF); if (res < 0) return res; - conf = swab16(res); - new_conf = conf; + new_conf = conf = res; new_conf &= ~attr->index; if (conf != new_conf) { - res = i2c_smbus_write_word_data(client, DS620_REG_CONF, - swab16(new_conf)); + res = i2c_smbus_write_word_swapped(client, DS620_REG_CONF, + new_conf); if (res < 0) return res; } diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index e7ae5743e181..a13e2da97e30 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -591,7 +591,7 @@ static int gl518_remove(struct i2c_client *client) static int gl518_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); + return i2c_smbus_read_word_swapped(client, reg); else return i2c_smbus_read_byte_data(client, reg); } @@ -599,7 +599,7 @@ static int gl518_read_value(struct i2c_client *client, u8 reg) static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) { if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); + return i2c_smbus_write_word_swapped(client, reg, value); else return i2c_smbus_write_byte_data(client, reg, value); } diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 131ea8625f08..cd6085bbfba7 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -821,7 +821,7 @@ static int gl520_remove(struct i2c_client *client) static int gl520_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); + return i2c_smbus_read_word_swapped(client, reg); else return i2c_smbus_read_byte_data(client, reg); } @@ -829,7 +829,7 @@ static int gl520_read_value(struct i2c_client *client, u8 reg) static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) { if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); + return i2c_smbus_write_word_swapped(client, reg, value); else return i2c_smbus_write_byte_data(client, reg, value); } diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 02cebb74e206..2d3d72805ff4 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -154,8 +154,6 @@ static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id); static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info); static int jc42_remove(struct i2c_client *client); -static int jc42_read_value(struct i2c_client *client, u8 reg); -static int jc42_write_value(struct i2c_client *client, u8 reg, u16 value); static struct jc42_data *jc42_update_device(struct device *dev); @@ -187,7 +185,7 @@ static int jc42_suspend(struct device *dev) struct jc42_data *data = i2c_get_clientdata(client); data->config |= JC42_CFG_SHUTDOWN; - jc42_write_value(client, JC42_REG_CONFIG, data->config); + i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, data->config); return 0; } @@ -197,7 +195,7 @@ static int jc42_resume(struct device *dev) struct jc42_data *data = i2c_get_clientdata(client); data->config &= ~JC42_CFG_SHUTDOWN; - jc42_write_value(client, JC42_REG_CONFIG, data->config); + i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, data->config); return 0; } @@ -315,7 +313,7 @@ static ssize_t set_##value(struct device *dev, \ return -EINVAL; \ mutex_lock(&data->update_lock); \ data->value = jc42_temp_to_reg(val, data->extended); \ - err = jc42_write_value(client, reg, data->value); \ + err = i2c_smbus_write_word_swapped(client, reg, data->value); \ if (err < 0) \ ret = err; \ mutex_unlock(&data->update_lock); \ @@ -357,7 +355,8 @@ static ssize_t set_temp_crit_hyst(struct device *dev, data->config = (data->config & ~(JC42_CFG_HYST_MASK << JC42_CFG_HYST_SHIFT)) | (hyst << JC42_CFG_HYST_SHIFT); - err = jc42_write_value(client, JC42_REG_CONFIG, data->config); + err = i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, + data->config); if (err < 0) ret = err; mutex_unlock(&data->update_lock); @@ -452,10 +451,10 @@ static int jc42_detect(struct i2c_client *new_client, I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - cap = jc42_read_value(new_client, JC42_REG_CAP); - config = jc42_read_value(new_client, JC42_REG_CONFIG); - manid = jc42_read_value(new_client, JC42_REG_MANID); - devid = jc42_read_value(new_client, JC42_REG_DEVICEID); + cap = i2c_smbus_read_word_swapped(new_client, JC42_REG_CAP); + config = i2c_smbus_read_word_swapped(new_client, JC42_REG_CONFIG); + manid = i2c_smbus_read_word_swapped(new_client, JC42_REG_MANID); + devid = i2c_smbus_read_word_swapped(new_client, JC42_REG_DEVICEID); if (cap < 0 || config < 0 || manid < 0 || devid < 0) return -ENODEV; @@ -489,14 +488,14 @@ static int jc42_probe(struct i2c_client *new_client, i2c_set_clientdata(new_client, data); mutex_init(&data->update_lock); - cap = jc42_read_value(new_client, JC42_REG_CAP); + cap = i2c_smbus_read_word_swapped(new_client, JC42_REG_CAP); if (cap < 0) { err = -EINVAL; goto exit_free; } data->extended = !!(cap & JC42_CAP_RANGE); - config = jc42_read_value(new_client, JC42_REG_CONFIG); + config = i2c_smbus_read_word_swapped(new_client, JC42_REG_CONFIG); if (config < 0) { err = -EINVAL; goto exit_free; @@ -504,7 +503,8 @@ static int jc42_probe(struct i2c_client *new_client, data->orig_config = config; if (config & JC42_CFG_SHUTDOWN) { config &= ~JC42_CFG_SHUTDOWN; - jc42_write_value(new_client, JC42_REG_CONFIG, config); + i2c_smbus_write_word_swapped(new_client, JC42_REG_CONFIG, + config); } data->config = config; @@ -535,25 +535,12 @@ static int jc42_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &jc42_group); if (data->config != data->orig_config) - jc42_write_value(client, JC42_REG_CONFIG, data->orig_config); + i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, + data->orig_config); kfree(data); return 0; } -/* All registers are word-sized. */ -static int jc42_read_value(struct i2c_client *client, u8 reg) -{ - int ret = i2c_smbus_read_word_data(client, reg); - if (ret < 0) - return ret; - return swab16(ret); -} - -static int jc42_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - static struct jc42_data *jc42_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -564,28 +551,29 @@ static struct jc42_data *jc42_update_device(struct device *dev) mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - val = jc42_read_value(client, JC42_REG_TEMP); + val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP); if (val < 0) { ret = ERR_PTR(val); goto abort; } data->temp_input = val; - val = jc42_read_value(client, JC42_REG_TEMP_CRITICAL); + val = i2c_smbus_read_word_swapped(client, + JC42_REG_TEMP_CRITICAL); if (val < 0) { ret = ERR_PTR(val); goto abort; } data->temp_crit = val; - val = jc42_read_value(client, JC42_REG_TEMP_LOWER); + val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER); if (val < 0) { ret = ERR_PTR(val); goto abort; } data->temp_min = val; - val = jc42_read_value(client, JC42_REG_TEMP_UPPER); + val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER); if (val < 0) { ret = ERR_PTR(val); goto abort; diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 24be17608fbb..9e64d96620d3 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -34,7 +34,7 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, #define LM73_REG_CTRL 0x04 #define LM73_REG_ID 0x07 -#define LM73_ID 0x9001 /* or 0x190 after a swab16() */ +#define LM73_ID 0x9001 /* 0x0190, byte-swapped */ #define DRVNAME "lm73" #define LM73_TEMP_MIN (-40) #define LM73_TEMP_MAX 150 @@ -57,7 +57,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, /* Write value */ value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4), (LM73_TEMP_MAX*4)) << 5; - i2c_smbus_write_word_data(client, attr->index, swab16(value)); + i2c_smbus_write_word_swapped(client, attr->index, value); return count; } @@ -68,8 +68,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da, struct i2c_client *client = to_i2c_client(dev); /* use integer division instead of equivalent right shift to guarantee arithmetic shift and preserve the sign */ - int temp = ((s16) (swab16(i2c_smbus_read_word_data(client, - attr->index)))*250) / 32; + int temp = ((s16) (i2c_smbus_read_word_swapped(client, + attr->index))*250) / 32; return sprintf(buf, "%d\n", temp); } diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 90126a2a1e44..1888dd0fc05f 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -384,13 +384,10 @@ static struct i2c_driver lm75_driver = { */ static int lm75_read_value(struct i2c_client *client, u8 reg) { - int value; - if (reg == LM75_REG_CONF) return i2c_smbus_read_byte_data(client, reg); - - value = i2c_smbus_read_word_data(client, reg); - return (value < 0) ? value : swab16(value); + else + return i2c_smbus_read_word_swapped(client, reg); } static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) @@ -398,7 +395,7 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) if (reg == LM75_REG_CONF) return i2c_smbus_write_byte_data(client, reg, value); else - return i2c_smbus_write_word_data(client, reg, swab16(value)); + return i2c_smbus_write_word_swapped(client, reg, value); } static struct lm75_data *lm75_update_device(struct device *dev) diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index b28a297be50c..8dfc6782d596 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -365,7 +365,7 @@ static u16 lm77_read_value(struct i2c_client *client, u8 reg) if (reg == LM77_REG_CONF) return i2c_smbus_read_byte_data(client, reg); else - return swab16(i2c_smbus_read_word_data(client, reg)); + return i2c_smbus_read_word_swapped(client, reg); } static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) @@ -373,7 +373,7 @@ static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) if (reg == LM77_REG_CONF) return i2c_smbus_write_byte_data(client, reg, value); else - return i2c_smbus_write_word_data(client, reg, swab16(value)); + return i2c_smbus_write_word_swapped(client, reg, value); } static void lm77_init_client(struct i2c_client *client) diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 7c31e6205f85..8fcbd4d422c5 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -117,16 +117,16 @@ static struct lm92_data *lm92_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { dev_dbg(&client->dev, "Updating lm92 data\n"); - data->temp1_input = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP)); - data->temp1_hyst = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HYST)); - data->temp1_crit = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_CRIT)); - data->temp1_min = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_LOW)); - data->temp1_max = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HIGH)); + data->temp1_input = i2c_smbus_read_word_swapped(client, + LM92_REG_TEMP); + data->temp1_hyst = i2c_smbus_read_word_swapped(client, + LM92_REG_TEMP_HYST); + data->temp1_crit = i2c_smbus_read_word_swapped(client, + LM92_REG_TEMP_CRIT); + data->temp1_min = i2c_smbus_read_word_swapped(client, + LM92_REG_TEMP_LOW); + data->temp1_max = i2c_smbus_read_word_swapped(client, + LM92_REG_TEMP_HIGH); data->last_updated = jiffies; data->valid = 1; @@ -158,7 +158,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co \ mutex_lock(&data->update_lock); \ data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_word_data(client, reg, swab16(data->value)); \ + i2c_smbus_write_word_swapped(client, reg, data->value); \ mutex_unlock(&data->update_lock); \ return count; \ } @@ -194,8 +194,8 @@ static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute * mutex_lock(&data->update_lock); data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; - i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST, - swab16(TEMP_TO_REG(data->temp1_hyst))); + i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, + TEMP_TO_REG(data->temp1_hyst)); mutex_unlock(&data->update_lock); return count; } diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index dd2d7b9620c2..385886a4f224 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -137,10 +137,10 @@ static int max16065_read_adc(struct i2c_client *client, int reg) { int rv; - rv = i2c_smbus_read_word_data(client, reg); + rv = i2c_smbus_read_word_swapped(client, reg); if (unlikely(rv < 0)) return rv; - return ((rv & 0xff) << 2) | ((rv >> 14) & 0x03); + return rv >> 6; } static struct max16065_data *max16065_update_device(struct device *dev) diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index 1c8c9812f244..15398780cc00 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -82,25 +82,6 @@ static inline int sht21_rh_ticks_to_per_cent_mille(int ticks) return ((15625 * ticks) >> 13) - 6000; } -/** - * sht21_read_word_data() - read word from register - * @client: I2C client device - * @reg: I2C command byte - * - * Returns value, negative errno on error. - */ -static inline int sht21_read_word_data(struct i2c_client *client, u8 reg) -{ - int ret = i2c_smbus_read_word_data(client, reg); - if (ret < 0) - return ret; - /* - * SMBus specifies low byte first, but the SHT21 returns MSB - * first, so we have to swab16 the values - */ - return swab16(ret); -} - /** * sht21_update_measurements() - get updated measurements from device * @client: I2C client device @@ -119,12 +100,13 @@ static int sht21_update_measurements(struct i2c_client *client) * maximum two measurements per second at 12bit accuracy shall be made. */ if (time_after(jiffies, sht21->last_update + HZ / 2) || !sht21->valid) { - ret = sht21_read_word_data(client, SHT21_TRIG_T_MEASUREMENT_HM); + ret = i2c_smbus_read_word_swapped(client, + SHT21_TRIG_T_MEASUREMENT_HM); if (ret < 0) goto out; sht21->temperature = sht21_temp_ticks_to_millicelsius(ret); - ret = sht21_read_word_data(client, - SHT21_TRIG_RH_MEASUREMENT_HM); + ret = i2c_smbus_read_word_swapped(client, + SHT21_TRIG_RH_MEASUREMENT_HM); if (ret < 0) goto out; sht21->humidity = sht21_rh_ticks_to_per_cent_mille(ret); diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index 425df5bccd45..411638181fd8 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -214,33 +214,26 @@ static int smm665_read_adc(struct smm665_data *data, int adc) * * Neither i2c_smbus_read_byte() nor * i2c_smbus_read_block_data() worked here, - * so use i2c_smbus_read_word_data() instead. + * so use i2c_smbus_read_word_swapped() instead. * We could also try to use i2c_master_recv(), * but that is not always supported. */ - rv = i2c_smbus_read_word_data(client, 0); + rv = i2c_smbus_read_word_swapped(client, 0); if (rv < 0) { dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv); return -1; } /* * Validate/verify readback adc channel (in bit 11..14). - * High byte is in lower 8 bit of rv, so only shift by 3. */ - radc = (rv >> 3) & 0x0f; + radc = (rv >> 11) & 0x0f; if (radc != adc) { dev_dbg(&client->dev, "Unexpected RADC: Expected %d got %d", adc, radc); return -EIO; } - /* - * Chip replies with H/L, while SMBus expects L/H. - * Thus, byte order is reversed, and we have to swap - * the result. - */ - rv = swab16(rv) & SMM665_ADC_MASK; - return rv; + return rv & SMM665_ADC_MASK; } static struct smm665_data *smm665_update_device(struct device *dev) diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 5bd194968801..643aa8c94535 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -55,19 +55,6 @@ struct tmp102 { int temp[3]; }; -/* SMBus specifies low byte first, but the TMP102 returns high byte first, - * so we have to swab16 the values */ -static inline int tmp102_read_reg(struct i2c_client *client, u8 reg) -{ - int result = i2c_smbus_read_word_data(client, reg); - return result < 0 ? result : swab16(result); -} - -static inline int tmp102_write_reg(struct i2c_client *client, u8 reg, u16 val) -{ - return i2c_smbus_write_word_data(client, reg, swab16(val)); -} - /* convert left adjusted 13-bit TMP102 register value to milliCelsius */ static inline int tmp102_reg_to_mC(s16 val) { @@ -94,7 +81,8 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client) if (time_after(jiffies, tmp102->last_update + HZ / 3)) { int i; for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) { - int status = tmp102_read_reg(client, tmp102_reg[i]); + int status = i2c_smbus_read_word_swapped(client, + tmp102_reg[i]); if (status > -1) tmp102->temp[i] = tmp102_reg_to_mC(status); } @@ -130,8 +118,8 @@ static ssize_t tmp102_set_temp(struct device *dev, mutex_lock(&tmp102->lock); tmp102->temp[sda->index] = val; - status = tmp102_write_reg(client, tmp102_reg[sda->index], - tmp102_mC_to_reg(val)); + status = i2c_smbus_write_word_swapped(client, tmp102_reg[sda->index], + tmp102_mC_to_reg(val)); mutex_unlock(&tmp102->lock); return status ? : count; } @@ -178,18 +166,19 @@ static int __devinit tmp102_probe(struct i2c_client *client, } i2c_set_clientdata(client, tmp102); - status = tmp102_read_reg(client, TMP102_CONF_REG); + status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { dev_err(&client->dev, "error reading config register\n"); goto fail_free; } tmp102->config_orig = status; - status = tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG); + status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, + TMP102_CONFIG); if (status < 0) { dev_err(&client->dev, "error writing config register\n"); goto fail_restore_config; } - status = tmp102_read_reg(client, TMP102_CONF_REG); + status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { dev_err(&client->dev, "error reading config register\n"); goto fail_restore_config; @@ -222,7 +211,8 @@ static int __devinit tmp102_probe(struct i2c_client *client, fail_remove_sysfs: sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group); fail_restore_config: - tmp102_write_reg(client, TMP102_CONF_REG, tmp102->config_orig); + i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, + tmp102->config_orig); fail_free: kfree(tmp102); @@ -240,10 +230,10 @@ static int __devexit tmp102_remove(struct i2c_client *client) if (tmp102->config_orig & TMP102_CONF_SD) { int config; - config = tmp102_read_reg(client, TMP102_CONF_REG); + config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (config >= 0) - tmp102_write_reg(client, TMP102_CONF_REG, - config | TMP102_CONF_SD); + i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, + config | TMP102_CONF_SD); } kfree(tmp102); @@ -257,12 +247,12 @@ static int tmp102_suspend(struct device *dev) struct i2c_client *client = to_i2c_client(dev); int config; - config = tmp102_read_reg(client, TMP102_CONF_REG); + config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (config < 0) return config; config |= TMP102_CONF_SD; - return tmp102_write_reg(client, TMP102_CONF_REG, config); + return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config); } static int tmp102_resume(struct device *dev) @@ -270,12 +260,12 @@ static int tmp102_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); int config; - config = tmp102_read_reg(client, TMP102_CONF_REG); + config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (config < 0) return config; config &= ~TMP102_CONF_SD; - return tmp102_write_reg(client, TMP102_CONF_REG, config); + return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config); } static const struct dev_pm_ops tmp102_dev_pm_ops = { diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index eed43a008be1..65b685e2c7b7 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1245,17 +1245,17 @@ w83781d_read_value_i2c(struct w83781d_data *data, u16 reg) /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data(cl, 0)); + res = i2c_smbus_read_word_swapped(cl, 0); break; case 0x52: /* CONFIG */ res = i2c_smbus_read_byte_data(cl, 1); break; case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data(cl, 2)); + res = i2c_smbus_read_word_swapped(cl, 2); break; case 0x55: /* OVER */ default: - res = swab16(i2c_smbus_read_word_data(cl, 3)); + res = i2c_smbus_read_word_swapped(cl, 3); break; } } @@ -1289,10 +1289,10 @@ w83781d_write_value_i2c(struct w83781d_data *data, u16 reg, u16 value) i2c_smbus_write_byte_data(cl, 1, value & 0xff); break; case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); + i2c_smbus_write_word_swapped(cl, 2, value); break; case 0x55: /* OVER */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); + i2c_smbus_write_word_swapped(cl, 3, value); break; } } From 2265cef2751b3441df91f85e0107f9f549e5b711 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:47 +0100 Subject: [PATCH 1407/1596] hwmon: (w83627ehf) Properly report PECI and AMD-SI sensor types When temperature sources are PECI or AMD-SI agents, it makes no sense to report their type as diode or thermistor. Instead we must report their digital nature. Signed-off-by: Jean Delvare Cc: stable@kernel.org Acked-by: Guenter Roeck --- drivers/hwmon/w83627ehf.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 98aab4bea342..9354f9541313 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1812,7 +1812,14 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, diode = 0x70; } for (i = 0; i < 3; i++) { - if ((tmp & (0x02 << i))) + const char *label = data->temp_label[data->temp_src[i]]; + + /* Digital source overrides analog type */ + if (strncmp(label, "PECI", 4) == 0) + data->temp_type[i] = 6; + else if (strncmp(label, "AMD", 3) == 0) + data->temp_type[i] = 5; + else if ((tmp & (0x02 << i))) data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3; else data->temp_type[i] = 4; /* thermistor */ From 6ba71de5f81bbf639b5dcea2bc2c33cdb87ed782 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:47 +0100 Subject: [PATCH 1408/1596] hwmon: (w83627ehf) Clean up probe function The probe function has grown pretty large, I think it's time for some cleanups, starting with these two simple ones: * Move temp3/in6 check for the W83667HG later in the function, where it is done for all other chip types. * Move temperature register setting to a separate function, to avoid code duplication. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83627ehf.c | 53 +++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 9354f9541313..81534cbd0aff 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1852,6 +1852,19 @@ static void w82627ehf_swap_tempreg(struct w83627ehf_data *data, data->reg_temp_config[r2] = tmp; } +static void __devinit +w83627ehf_set_temp_reg_ehf(struct w83627ehf_data *data, int n_temp) +{ + int i; + + for (i = 0; i < n_temp; i++) { + data->reg_temp[i] = W83627EHF_REG_TEMP[i]; + data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i]; + data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i]; + data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i]; + } +} + static void __devinit w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data, struct w83627ehf_data *data) @@ -1955,17 +1968,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) || sio_data->kind == nct6775 || sio_data->kind == nct6776) ? 3 : 4; + /* Default to 3 temperature inputs, code below will adjust as needed */ data->have_temp = 0x07; - /* Check temp3 configuration bit for 667HG */ - if (sio_data->kind == w83667hg) { - u8 reg; - - reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]); - if (reg & 0x01) - data->have_temp &= ~(1 << 2); - else - data->in6_skip = 1; /* either temp3 or in6 */ - } /* Deal with temperature register setup first. */ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { @@ -2042,16 +2046,12 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) } else if (sio_data->kind == w83667hg_b) { u8 reg; + w83627ehf_set_temp_reg_ehf(data, 4); + /* * Temperature sources are selected with bank 0, registers 0x49 * and 0x4a. */ - for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) { - data->reg_temp[i] = W83627EHF_REG_TEMP[i]; - data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i]; - data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i]; - data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i]; - } reg = w83627ehf_read_value(data, 0x4a); data->temp_src[0] = reg >> 5; reg = w83627ehf_read_value(data, 0x49); @@ -2086,12 +2086,23 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) data->temp_label = w83667hg_b_temp_label; } else { + w83627ehf_set_temp_reg_ehf(data, 3); + /* Temperature sources are fixed */ - for (i = 0; i < 3; i++) { - data->reg_temp[i] = W83627EHF_REG_TEMP[i]; - data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i]; - data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i]; - data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i]; + + if (sio_data->kind == w83667hg) { + u8 reg; + + /* + * Chip supports either AUXTIN or VIN3. Try to find + * out which one. + */ + reg = w83627ehf_read_value(data, + W83627EHF_REG_TEMP_CONFIG[2]); + if (reg & 0x01) + data->have_temp &= ~(1 << 2); + else + data->in6_skip = 1; } } From eff7687d473c31cba3876c13e97eebc708eb8582 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:48 +0100 Subject: [PATCH 1409/1596] hwmon: (w83627ehf) Add support for the W83627UHG This is essentially a stripped down version of the W83627DHG. Noticeable difference is that it is still powered with +5V, as older models, even though the ADC resolution is 8 mV as newer models have. Thanks to Ulf Bruman (Saab Group) for doing all the testing. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- Documentation/hwmon/w83627ehf | 28 ++++--- drivers/hwmon/Kconfig | 5 +- drivers/hwmon/w83627ehf.c | 148 ++++++++++++++++++++++++++++------ 3 files changed, 140 insertions(+), 41 deletions(-) diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index 76ffef94ed75..3f44dbdfda70 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -14,6 +14,10 @@ Supported chips: Prefix: 'w83627dhg' Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: not available + * Winbond W83627UHG + Prefix: 'w83627uhg' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: available from www.nuvoton.com * Winbond W83667HG Prefix: 'w83667hg' Addresses scanned: ISA address retrieved from Super I/O registers @@ -42,14 +46,13 @@ Description ----------- This driver implements support for the Winbond W83627EHF, W83627EHG, -W83627DHG, W83627DHG-P, W83667HG, W83667HG-B, W83667HG-I (NCT6775F), -and NCT6776F super I/O chips. We will refer to them collectively as -Winbond chips. - -The chips implement three temperature sensors (up to four for 667HG-B, and nine -for NCT6775F and NCT6776F), five fan rotation speed sensors, ten analog voltage -sensors (only nine for the 627DHG), one VID (6 pins for the 627EHF/EHG, 8 pins -for the 627DHG and 667HG), alarms with beep warnings (control unimplemented), +W83627DHG, W83627DHG-P, W83627UHG, W83667HG, W83667HG-B, W83667HG-I +(NCT6775F), and NCT6776F super I/O chips. We will refer to them collectively +as Winbond chips. + +The chips implement 2 to 4 temperature sensors (9 for NCT6775F and NCT6776F), +2 to 5 fan rotation speed sensors, 8 to 10 analog voltage sensors, one VID +(except for 627UHG), alarms with beep warnings (control unimplemented), and some automatic fan regulation strategies (plus manual fan control mode). The temperature sensor sources on W82677HG-B, NCT6775F, and NCT6776F are @@ -86,17 +89,16 @@ follows: temp1 -> pwm1 temp2 -> pwm2 -temp3 -> pwm3 +temp3 -> pwm3 (not on 627UHG) prog -> pwm4 (not on 667HG and 667HG-B; the programmable setting is not supported by the driver) /sys files ---------- -name - this is a standard hwmon device entry. For the W83627EHF and W83627EHG, - it is set to "w83627ehf", for the W83627DHG it is set to "w83627dhg", - for the W83667HG and W83667HG-B it is set to "w83667hg", for NCT6775F it - is set to "nct6775", and for NCT6776F it is set to "nct6776". +name - this is a standard hwmon device entry, it contains the name of + the device (see the prefix in the list of supported devices at + the top of this file) pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range: 0 (stop) to 255 (full) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 279a509dca9f..9ec854ae118b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1282,7 +1282,7 @@ config SENSORS_W83627HF will be called w83627hf. config SENSORS_W83627EHF - tristate "Winbond W83627EHF/EHG/DHG, W83667HG, NCT6775F, NCT6776F" + tristate "Winbond W83627EHF/EHG/DHG/UHG, W83667HG, NCT6775F, NCT6776F" depends on !PPC select HWMON_VID help @@ -1292,7 +1292,8 @@ config SENSORS_W83627EHF This driver also supports the W83627EHG, which is the lead-free version of the W83627EHF, and the W83627DHG, which is a similar chip suited for specific Intel processors that use PECI such as - the Core 2 Duo. + the Core 2 Duo. And also the W83627UHG, which is a stripped down + version of the W83627DHG (as far as hardware monitoring goes.) This driver also supports Nuvoton W83667HG, W83667HG-B, NCT6775F (also known as W83667HG-I), and NCT6776F. diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 81534cbd0aff..483cb268781e 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1,7 +1,7 @@ /* w83627ehf - Driver for the hardware monitoring functionality of the Winbond W83627EHF Super-I/O chip - Copyright (C) 2005 Jean Delvare + Copyright (C) 2005-2011 Jean Delvare Copyright (C) 2006 Yuan Mu (Winbond), Rudolf Marek David Hubbard @@ -39,6 +39,7 @@ 0x8860 0xa1 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 + w83627uhg 8 2 2 2 0xa230 0xc1 0x5ca3 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3 nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3 @@ -61,14 +62,17 @@ #include #include "lm75.h" -enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775, - nct6776 }; +enum kinds { + w83627ehf, w83627dhg, w83627dhg_p, w83627uhg, + w83667hg, w83667hg_b, nct6775, nct6776, +}; /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ static const char * const w83627ehf_device_names[] = { "w83627ehf", "w83627dhg", "w83627dhg", + "w83627uhg", "w83667hg", "w83667hg", "nct6775", @@ -104,6 +108,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_W83627EHG_ID 0x8860 #define SIO_W83627DHG_ID 0xa020 #define SIO_W83627DHG_P_ID 0xb070 +#define SIO_W83627UHG_ID 0xa230 #define SIO_W83667HG_ID 0xa510 #define SIO_W83667HG_B_ID 0xb350 #define SIO_NCT6775_ID 0xb470 @@ -388,18 +393,23 @@ div_from_reg(u8 reg) return 1 << reg; } -/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */ - -static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 }; +/* Some of the voltage inputs have internal scaling, the tables below + * contain 8 (the ADC LSB in mV) * scaling factor * 100 */ +static const u16 scale_in_common[10] = { + 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800 +}; +static const u16 scale_in_w83627uhg[9] = { + 800, 800, 3328, 3424, 800, 800, 0, 3328, 3400 +}; -static inline long in_from_reg(u8 reg, u8 nr) +static inline long in_from_reg(u8 reg, u8 nr, const u16 *scale_in) { - return reg * scale_in[nr]; + return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100); } -static inline u8 in_to_reg(u32 val, u8 nr) +static inline u8 in_to_reg(u32 val, u8 nr, const u16 *scale_in) { - return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, + return SENSORS_LIMIT(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255); } @@ -430,6 +440,7 @@ struct w83627ehf_data { const u16 *REG_FAN_STOP_TIME; const u16 *REG_FAN_MAX_OUTPUT; const u16 *REG_FAN_STEP_OUTPUT; + const u16 *scale_in; unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg); unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg); @@ -481,7 +492,8 @@ struct w83627ehf_data { u8 vrm; u16 have_temp; - u8 in6_skip; + u8 in6_skip:1; + u8 temp3_val_only:1; }; struct w83627ehf_sio_data { @@ -907,7 +919,8 @@ show_##reg(struct device *dev, struct device_attribute *attr, \ struct sensor_device_attribute *sensor_attr = \ to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ - return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \ + return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr, \ + data->scale_in)); \ } show_in_reg(in) show_in_reg(in_min) @@ -928,7 +941,7 @@ store_in_##reg(struct device *dev, struct device_attribute *attr, \ if (err < 0) \ return err; \ mutex_lock(&data->update_lock); \ - data->in_##reg[nr] = in_to_reg(val, nr); \ + data->in_##reg[nr] = in_to_reg(val, nr, data->scale_in); \ w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \ data->in_##reg[nr]); \ mutex_unlock(&data->update_lock); \ @@ -1617,25 +1630,28 @@ static struct sensor_device_attribute sda_sf3_arrays_fan4[] = { store_fan_step_output, 3), }; +static struct sensor_device_attribute sda_sf3_arrays_fan3[] = { + SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, + store_fan_stop_time, 2), + SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, + store_fan_start_output, 2), + SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, + store_fan_stop_output, 2), +}; + static struct sensor_device_attribute sda_sf3_arrays[] = { SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, store_fan_stop_time, 0), SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, store_fan_stop_time, 1), - SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, - store_fan_stop_time, 2), SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, store_fan_start_output, 0), SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, store_fan_start_output, 1), - SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, - store_fan_start_output, 2), SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, store_fan_stop_output, 0), SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, store_fan_stop_output, 1), - SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, - store_fan_stop_output, 2), }; @@ -1728,6 +1744,8 @@ static void w83627ehf_device_remove_files(struct device *dev) data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) device_remove_file(dev, &attr->dev_attr); } + for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan3); i++) + device_remove_file(dev, &sda_sf3_arrays_fan3[i].dev_attr); for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); for (i = 0; i < data->in_num; i++) { @@ -1756,6 +1774,8 @@ static void w83627ehf_device_remove_files(struct device *dev) continue; device_remove_file(dev, &sda_temp_input[i].dev_attr); device_remove_file(dev, &sda_temp_label[i].dev_attr); + if (i == 2 && data->temp3_val_only) + continue; device_remove_file(dev, &sda_temp_max[i].dev_attr); device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); if (i > 2) @@ -1808,6 +1828,9 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, case w83627ehf: diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE); break; + case w83627uhg: + diode = 0x00; + break; default: diode = 0x70; } @@ -1871,6 +1894,13 @@ w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data, { int fan3pin, fan4pin, fan4min, fan5pin, regval; + /* The W83627UHG is simple, only two fan inputs, no config */ + if (sio_data->kind == w83627uhg) { + data->has_fan = 0x03; /* fan1 and fan2 */ + data->has_fan_min = 0x03; + return; + } + superio_enter(sio_data->sioreg); /* fan4 and fan5 share some pins with the GPIO and serial flash */ @@ -1962,11 +1992,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9; - /* 667HG, NCT6775F, and NCT6776F have 3 pwms */ - data->pwm_num = (sio_data->kind == w83667hg - || sio_data->kind == w83667hg_b - || sio_data->kind == nct6775 - || sio_data->kind == nct6776) ? 3 : 4; + /* 667HG, NCT6775F, and NCT6776F have 3 pwms, and 627UHG has only 2 */ + switch (sio_data->kind) { + default: + data->pwm_num = 4; + break; + case w83667hg: + case w83667hg_b: + case nct6775: + case nct6776: + data->pwm_num = 3; + break; + case w83627uhg: + data->pwm_num = 2; + break; + } /* Default to 3 temperature inputs, code below will adjust as needed */ data->have_temp = 0x07; @@ -2084,6 +2124,42 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3)))) data->in6_skip = 1; + data->temp_label = w83667hg_b_temp_label; + } else if (sio_data->kind == w83627uhg) { + u8 reg; + + w83627ehf_set_temp_reg_ehf(data, 3); + + /* + * Temperature sources for temp1 and temp2 are selected with + * bank 0, registers 0x49 and 0x4a. + */ + data->temp_src[0] = 0; /* SYSTIN */ + reg = w83627ehf_read_value(data, 0x49) & 0x07; + /* Adjust to have the same mapping as other source registers */ + if (reg == 0) + data->temp_src[1]++; + else if (reg >= 2 && reg <= 5) + data->temp_src[1] += 2; + else /* should never happen */ + data->have_temp &= ~(1 << 1); + reg = w83627ehf_read_value(data, 0x4a); + data->temp_src[2] = reg >> 5; + + /* + * Skip temp3 if source is invalid or the same as temp1 + * or temp2. + */ + if (data->temp_src[2] == 2 || data->temp_src[2] == 3 || + data->temp_src[2] == data->temp_src[0] || + ((data->have_temp & (1 << 1)) && + data->temp_src[2] == data->temp_src[1])) + data->have_temp &= ~(1 << 2); + else + data->temp3_val_only = 1; /* No limit regs */ + + data->in6_skip = 1; /* No VIN3 */ + data->temp_label = w83667hg_b_temp_label; } else { w83627ehf_set_temp_reg_ehf(data, 3); @@ -2162,6 +2238,12 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) W83627EHF_REG_FAN_STEP_OUTPUT_COMMON; } + /* Setup input voltage scaling factors */ + if (sio_data->kind == w83627uhg) + data->scale_in = scale_in_w83627uhg; + else + data->scale_in = scale_in_common; + /* Initialize the chip */ w83627ehf_init_device(data, sio_data->kind); @@ -2178,7 +2260,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) err = device_create_file(dev, &dev_attr_cpu0_vid); if (err) goto exit_release; - } else { + } else if (sio_data->kind != w83627uhg) { superio_select(sio_data->sioreg, W83627EHF_LD_HWM); if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { /* Set VID input sensibility if needed. In theory the @@ -2268,7 +2350,14 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) goto exit_remove; } } - /* if fan4 is enabled create the sf3 files for it */ + /* if fan3 and fan4 are enabled create the sf3 files for them */ + if ((data->has_fan & (1 << 2)) && data->pwm_num >= 3) + for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan3); i++) { + err = device_create_file(dev, + &sda_sf3_arrays_fan3[i].dev_attr); + if (err) + goto exit_remove; + } if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4) for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { err = device_create_file(dev, @@ -2336,6 +2425,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) if (err) goto exit_remove; } + if (i == 2 && data->temp3_val_only) + continue; if (data->reg_temp_over[i]) { err = device_create_file(dev, &sda_temp_max[i].dev_attr); @@ -2419,6 +2510,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; + static const char __initdata sio_name_W83627UHG[] = "W83627UHG"; static const char __initdata sio_name_W83667HG[] = "W83667HG"; static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B"; static const char __initdata sio_name_NCT6775[] = "NCT6775F"; @@ -2451,6 +2543,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, sio_data->kind = w83627dhg_p; sio_name = sio_name_W83627DHG_P; break; + case SIO_W83627UHG_ID: + sio_data->kind = w83627uhg; + sio_name = sio_name_W83627UHG; + break; case SIO_W83667HG_ID: sio_data->kind = w83667hg; sio_name = sio_name_W83667HG; From 6070295efc90d1093b2031c43380bd7d9673c802 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 4 Nov 2011 07:04:10 -0400 Subject: [PATCH 1410/1596] nfs: set vs_hidden on nfs4_callback_version4 (try #2) This service should not be registered with or unregistered from rpcbind. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/callback_xdr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index ee1a5b3cd48d..726e59a9e50f 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -987,4 +987,5 @@ struct svc_version nfs4_callback_version4 = { .vs_proc = nfs4_callback_procedures1, .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, .vs_dispatch = NULL, + .vs_hidden = 1, }; From dd2c0ca1b153b555c09fd8e08f6842e12cf8e87b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 19 Sep 2011 18:51:13 -0700 Subject: [PATCH 1411/1596] sh: clkfwk: add clk_rate_mult_range_round() This provides a clk_rate_mult_range_round() helper for use by some of the CPG PLL ranged multipliers, following the same approach as used by the div ranges. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 20 ++++++++++++++++++++ include/linux/sh_clk.h | 3 +++ 2 files changed, 23 insertions(+) diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index dc8d022c07a1..352036b1f9a2 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -173,6 +173,26 @@ long clk_rate_div_range_round(struct clk *clk, unsigned int div_min, return clk_rate_round_helper(&div_range_round); } +static long clk_rate_mult_range_iter(unsigned int pos, + struct clk_rate_round_data *rounder) +{ + return clk_get_rate(rounder->arg) * pos; +} + +long clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min, + unsigned int mult_max, unsigned long rate) +{ + struct clk_rate_round_data mult_range_round = { + .min = mult_min, + .max = mult_max, + .func = clk_rate_mult_range_iter, + .arg = clk_get_parent(clk), + .rate = rate, + }; + + return clk_rate_round_helper(&mult_range_round); +} + int clk_rate_table_find(struct clk *clk, struct cpufreq_frequency_table *freq_table, unsigned long rate) diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index 3ccf18648d0a..9237c299641c 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h @@ -94,6 +94,9 @@ int clk_rate_table_find(struct clk *clk, long clk_rate_div_range_round(struct clk *clk, unsigned int div_min, unsigned int div_max, unsigned long rate); +long clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min, + unsigned int mult_max, unsigned long rate); + long clk_round_parent(struct clk *clk, unsigned long target, unsigned long *best_freq, unsigned long *parent_freq, unsigned int div_min, unsigned int div_max); From d6e15eefcb334deac3e877fce80ace3b91b0ab69 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 Oct 2011 16:21:00 +0900 Subject: [PATCH 1412/1596] ARM: mach-shmobile: Break out INTC IRQ code Add INTC_IRQ_PINS_16() and INTC_IRQ_PINS_32() to mach/intc.h. These macros define 16 or 32 external IRQ pins on a certain memory base address. Can be used with INTCA or INTCS. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/include/mach/intc.h | 195 +++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 arch/arm/mach-shmobile/include/mach/intc.h diff --git a/arch/arm/mach-shmobile/include/mach/intc.h b/arch/arm/mach-shmobile/include/mach/intc.h new file mode 100644 index 000000000000..1cd8b36678ee --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/intc.h @@ -0,0 +1,195 @@ +#ifndef __ASM_MACH_INTC_H +#define __ASM_MACH_INTC_H +#include + +#define INTC_IRQ_PINS_ENUM_16L(p) \ + p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \ + p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7, \ + p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \ + p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 + +#define INTC_IRQ_PINS_ENUM_16H(p) \ + p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \ + p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23, \ + p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \ + p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 + +#define INTC_IRQ_PINS_VECT_16L(p, vect) \ + vect(p ## _IRQ0, 0x0200), vect(p ## _IRQ1, 0x0220), \ + vect(p ## _IRQ2, 0x0240), vect(p ## _IRQ3, 0x0260), \ + vect(p ## _IRQ4, 0x0280), vect(p ## _IRQ5, 0x02a0), \ + vect(p ## _IRQ6, 0x02c0), vect(p ## _IRQ7, 0x02e0), \ + vect(p ## _IRQ8, 0x0300), vect(p ## _IRQ9, 0x0320), \ + vect(p ## _IRQ10, 0x0340), vect(p ## _IRQ11, 0x0360), \ + vect(p ## _IRQ12, 0x0380), vect(p ## _IRQ13, 0x03a0), \ + vect(p ## _IRQ14, 0x03c0), vect(p ## _IRQ15, 0x03e0) + +#define INTC_IRQ_PINS_VECT_16H(p, vect) \ + vect(p ## _IRQ16, 0x3200), vect(p ## _IRQ17, 0x3220), \ + vect(p ## _IRQ18, 0x3240), vect(p ## _IRQ19, 0x3260), \ + vect(p ## _IRQ20, 0x3280), vect(p ## _IRQ21, 0x32a0), \ + vect(p ## _IRQ22, 0x32c0), vect(p ## _IRQ23, 0x32e0), \ + vect(p ## _IRQ24, 0x3300), vect(p ## _IRQ25, 0x3320), \ + vect(p ## _IRQ26, 0x3340), vect(p ## _IRQ27, 0x3360), \ + vect(p ## _IRQ28, 0x3380), vect(p ## _IRQ29, 0x33a0), \ + vect(p ## _IRQ30, 0x33c0), vect(p ## _IRQ31, 0x33e0) + +#define INTC_IRQ_PINS_MASK_16L(p, base) \ + { base + 0x40, base + 0x60, 8, /* INTMSK00A / INTMSKCLR00A */ \ + { p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \ + p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7 } }, \ + { base + 0x44, base + 0x64, 8, /* INTMSK10A / INTMSKCLR10A */ \ + { p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \ + p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 } } + +#define INTC_IRQ_PINS_MASK_16H(p, base) \ + { base + 0x48, base + 0x68, 8, /* INTMSK20A / INTMSKCLR20A */ \ + { p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \ + p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23 } }, \ + { base + 0x4c, base + 0x6c, 8, /* INTMSK30A / INTMSKCLR30A */ \ + { p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \ + p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 } } + +#define INTC_IRQ_PINS_PRIO_16L(p, base) \ + { base + 0x10, 0, 32, 4, /* INTPRI00A */ \ + { p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \ + p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7 } }, \ + { base + 0x14, 0, 32, 4, /* INTPRI10A */ \ + { p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \ + p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 } } + +#define INTC_IRQ_PINS_PRIO_16H(p, base) \ + { base + 0x18, 0, 32, 4, /* INTPRI20A */ \ + { p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \ + p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23 } }, \ + { base + 0x1c, 0, 32, 4, /* INTPRI30A */ \ + { p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \ + p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 } } + +#define INTC_IRQ_PINS_SENSE_16L(p, base) \ + { base + 0x00, 32, 4, /* ICR1A */ \ + { p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \ + p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7 } }, \ + { base + 0x04, 32, 4, /* ICR2A */ \ + { p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \ + p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 } } + +#define INTC_IRQ_PINS_SENSE_16H(p, base) \ + { base + 0x08, 32, 4, /* ICR3A */ \ + { p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \ + p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23 } }, \ + { base + 0x0c, 32, 4, /* ICR4A */ \ + { p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \ + p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 } } + +#define INTC_IRQ_PINS_ACK_16L(p, base) \ + { base + 0x20, 0, 8, /* INTREQ00A */ \ + { p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \ + p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7 } }, \ + { base + 0x24, 0, 8, /* INTREQ10A */ \ + { p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \ + p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 } } + +#define INTC_IRQ_PINS_ACK_16H(p, base) \ + { base + 0x28, 0, 8, /* INTREQ20A */ \ + { p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \ + p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23 } }, \ + { base + 0x2c, 0, 8, /* INTREQ30A */ \ + { p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \ + p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 } } + +#define INTC_IRQ_PINS_16(p, base, vect, str) \ + \ +static struct resource p ## _resources[] __initdata = { \ + [0] = { \ + .start = base, \ + .end = base + 0x64, \ + .flags = IORESOURCE_MEM, \ + }, \ +}; \ + \ +enum { \ + p ## _UNUSED = 0, \ + INTC_IRQ_PINS_ENUM_16L(p), \ +}; \ + \ +static struct intc_vect p ## _vectors[] __initdata = { \ + INTC_IRQ_PINS_VECT_16L(p, vect), \ +}; \ + \ +static struct intc_mask_reg p ## _mask_registers[] __initdata = { \ + INTC_IRQ_PINS_MASK_16L(p, base), \ +}; \ + \ +static struct intc_prio_reg p ## _prio_registers[] __initdata = { \ + INTC_IRQ_PINS_PRIO_16L(p, base), \ +}; \ + \ +static struct intc_sense_reg p ## _sense_registers[] __initdata = { \ + INTC_IRQ_PINS_SENSE_16L(p, base), \ +}; \ + \ +static struct intc_mask_reg p ## _ack_registers[] __initdata = { \ + INTC_IRQ_PINS_ACK_16L(p, base), \ +}; \ + \ +static struct intc_desc p ## _desc __initdata = { \ + .name = str, \ + .resource = p ## _resources, \ + .num_resources = ARRAY_SIZE(p ## _resources), \ + .hw = INTC_HW_DESC(p ## _vectors, NULL, \ + p ## _mask_registers, p ## _prio_registers, \ + p ## _sense_registers, p ## _ack_registers) \ +} + +#define INTC_IRQ_PINS_32(p, base, vect, str) \ + \ +static struct resource p ## _resources[] __initdata = { \ + [0] = { \ + .start = base, \ + .end = base + 0x6c, \ + .flags = IORESOURCE_MEM, \ + }, \ +}; \ + \ +enum { \ + p ## _UNUSED = 0, \ + INTC_IRQ_PINS_ENUM_16L(p), \ + INTC_IRQ_PINS_ENUM_16H(p), \ +}; \ + \ +static struct intc_vect p ## _vectors[] __initdata = { \ + INTC_IRQ_PINS_VECT_16L(p, vect), \ + INTC_IRQ_PINS_VECT_16H(p, vect), \ +}; \ + \ +static struct intc_mask_reg p ## _mask_registers[] __initdata = { \ + INTC_IRQ_PINS_MASK_16L(p, base), \ + INTC_IRQ_PINS_MASK_16H(p, base), \ +}; \ + \ +static struct intc_prio_reg p ## _prio_registers[] __initdata = { \ + INTC_IRQ_PINS_PRIO_16L(p, base), \ + INTC_IRQ_PINS_PRIO_16H(p, base), \ +}; \ + \ +static struct intc_sense_reg p ## _sense_registers[] __initdata = { \ + INTC_IRQ_PINS_SENSE_16L(p, base), \ + INTC_IRQ_PINS_SENSE_16H(p, base), \ +}; \ + \ +static struct intc_mask_reg p ## _ack_registers[] __initdata = { \ + INTC_IRQ_PINS_ACK_16L(p, base), \ + INTC_IRQ_PINS_ACK_16H(p, base), \ +}; \ + \ +static struct intc_desc p ## _desc __initdata = { \ + .name = str, \ + .resource = p ## _resources, \ + .num_resources = ARRAY_SIZE(p ## _resources), \ + .hw = INTC_HW_DESC(p ## _vectors, NULL, \ + p ## _mask_registers, p ## _prio_registers, \ + p ## _sense_registers, p ## _ack_registers) \ +} + +#endif /* __ASM_MACH_INTC_H */ From 7d377b170ae0d4df7692f50c9609bea385fe87cc Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 Oct 2011 16:21:08 +0900 Subject: [PATCH 1413/1596] sh: intc: Allow triggering on both edges for ARM SoCs Enable IRQ_TYPE_EDGE_BOTH on all R/SH-Mobile ARM SoCs. This hardware feature is supported by sh7367, sh7377, sh7372 and sh73a0. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/sh/intc/chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c index e0ada3773786..7b246efa94ea 100644 --- a/drivers/sh/intc/chip.c +++ b/drivers/sh/intc/chip.c @@ -186,7 +186,7 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { !defined(CONFIG_CPU_SUBTYPE_SH7709) [IRQ_TYPE_LEVEL_HIGH] = VALID(3), #endif -#if defined(CONFIG_ARCH_SH7372) +#if defined(CONFIG_ARM) /* all recent SH-Mobile / R-Mobile ARM support this */ [IRQ_TYPE_EDGE_BOTH] = VALID(4), #endif }; From 487881c09b3a34735b0d1c71666703b8f0f10d8f Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 27 Sep 2011 18:29:31 +0900 Subject: [PATCH 1414/1596] ARM: mach-shmobile: sh7372 Mackerel NOR Flash USB boot fix Always use CS0 shadow area for NOR flash instead of regular CS0 memory area on Mackerel. When booting from CS0 NOR Flash the regular CS0 memory area is available, but when booting via USB the MASK ROM gets mapped to 0x0 which gets in the way for the NOR Flash. Always using CS0 shadow area works well for both NOR Flash boot and USB boot. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-mackerel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 3689ad2e9156..6c621c2ce0bc 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -273,8 +273,8 @@ static struct physmap_flash_data nor_flash_data = { static struct resource nor_flash_resources[] = { [0] = { - .start = 0x00000000, - .end = 0x08000000 - 1, + .start = 0x20000000, /* CS0 shadow instead of regular CS0 */ + .end = 0x28000000 - 1, /* needed by USB MASK ROM boot */ .flags = IORESOURCE_MEM, } }; From 832217daec1aa8683c037e8e0e0b910ea24fbca5 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Tue, 27 Sep 2011 13:23:04 +0200 Subject: [PATCH 1415/1596] ARM: sh7372 ap4evb NOR Flash USB boot fix Always use CS0 shadow area for NOR flash instead of regular CS0 memory area on ap4evb. When booting from CS0 NOR Flash the regular CS0 memory area is available, but when booting via USB the MASK ROM gets mapped to 0x0 which gets in the way for the NOR Flash. Always using CS0 shadow area works well for both NOR Flash boot and USB boot. Signed-off-by: Bastian Hecht Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 5b7edadf4647..7283d6913fbf 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -200,8 +200,8 @@ static struct physmap_flash_data nor_flash_data = { static struct resource nor_flash_resources[] = { [0] = { - .start = 0x00000000, - .end = 0x08000000 - 1, + .start = 0x20000000, /* CS0 shadow instead of regular CS0 */ + .end = 0x28000000 - 1, /* needed by USB MASK ROM boot */ .flags = IORESOURCE_MEM, } }; From 13fc7e7c2cd08a884f76eeb940957160b296d5c3 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 28 Sep 2011 16:55:45 +0900 Subject: [PATCH 1416/1596] ARM: mach-shmobile: sh73a0 GPIO IRQ support This patch adds support for sh73a0 GPIO IRQs by making use of the PFC GPIO IRQ feature. Only IRQ pins are supported at this time. In the future when PINT interrupts also are supported properly we can easily extend the table with such information. Also, the sh73a0 is currently making use of the GIC for external interrupt which is rather unflexible when it comes to triggering configuration at this point. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/pfc-sh73a0.c | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/arm/mach-shmobile/pfc-sh73a0.c b/arch/arm/mach-shmobile/pfc-sh73a0.c index a26d9059036b..57322c9fd9b6 100644 --- a/arch/arm/mach-shmobile/pfc-sh73a0.c +++ b/arch/arm/mach-shmobile/pfc-sh73a0.c @@ -22,6 +22,7 @@ #include #include #include +#include #define _1(fn, pfx, sfx) fn(pfx, sfx) @@ -2765,6 +2766,43 @@ static struct pinmux_data_reg pinmux_data_regs[] = { { }, }; +#define EXT_IRQ(n) gic_spi((n) + 1) /* GIC SPI starting from 1 for IRQ0 */ + +static struct pinmux_irq pinmux_irqs[] = { + PINMUX_IRQ(EXT_IRQ(19), PORT9_FN0), + PINMUX_IRQ(EXT_IRQ(1), PORT10_FN0), + PINMUX_IRQ(EXT_IRQ(0), PORT11_FN0), + PINMUX_IRQ(EXT_IRQ(18), PORT13_FN0), + PINMUX_IRQ(EXT_IRQ(20), PORT14_FN0), + PINMUX_IRQ(EXT_IRQ(21), PORT15_FN0), + PINMUX_IRQ(EXT_IRQ(31), PORT26_FN0), + PINMUX_IRQ(EXT_IRQ(30), PORT27_FN0), + PINMUX_IRQ(EXT_IRQ(29), PORT28_FN0), + PINMUX_IRQ(EXT_IRQ(22), PORT40_FN0), + PINMUX_IRQ(EXT_IRQ(23), PORT53_FN0), + PINMUX_IRQ(EXT_IRQ(10), PORT54_FN0), + PINMUX_IRQ(EXT_IRQ(9), PORT56_FN0), + PINMUX_IRQ(EXT_IRQ(26), PORT115_FN0), + PINMUX_IRQ(EXT_IRQ(27), PORT116_FN0), + PINMUX_IRQ(EXT_IRQ(28), PORT117_FN0), + PINMUX_IRQ(EXT_IRQ(24), PORT118_FN0), + PINMUX_IRQ(EXT_IRQ(6), PORT147_FN0), + PINMUX_IRQ(EXT_IRQ(2), PORT149_FN0), + PINMUX_IRQ(EXT_IRQ(7), PORT150_FN0), + PINMUX_IRQ(EXT_IRQ(12), PORT156_FN0), + PINMUX_IRQ(EXT_IRQ(4), PORT159_FN0), + PINMUX_IRQ(EXT_IRQ(25), PORT164_FN0), + PINMUX_IRQ(EXT_IRQ(8), PORT223_FN0), + PINMUX_IRQ(EXT_IRQ(3), PORT224_FN0), + PINMUX_IRQ(EXT_IRQ(5), PORT227_FN0), + PINMUX_IRQ(EXT_IRQ(17), PORT234_FN0), + PINMUX_IRQ(EXT_IRQ(11), PORT238_FN0), + PINMUX_IRQ(EXT_IRQ(13), PORT239_FN0), + PINMUX_IRQ(EXT_IRQ(16), PORT249_FN0), + PINMUX_IRQ(EXT_IRQ(14), PORT251_FN0), + PINMUX_IRQ(EXT_IRQ(9), PORT308_FN0), +}; + static struct pinmux_info sh73a0_pinmux_info = { .name = "sh73a0_pfc", .reserved_id = PINMUX_RESERVED, @@ -2785,6 +2823,9 @@ static struct pinmux_info sh73a0_pinmux_info = { .gpio_data = pinmux_data, .gpio_data_size = ARRAY_SIZE(pinmux_data), + + .gpio_irq = pinmux_irqs, + .gpio_irq_size = ARRAY_SIZE(pinmux_irqs), }; void sh73a0_pinmux_init(void) From e753068093c4c4da80771bd5ee53a6a782dee7b6 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 Oct 2011 16:21:16 +0900 Subject: [PATCH 1417/1596] ARM: mach-shmobile: Use common INTC IRQ code on sh7367 Make use of INTC_IRQ_PINS_16() for INTCA on sh7367. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh7367.c | 40 +++++----------------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/arch/arm/mach-shmobile/intc-sh7367.c b/arch/arm/mach-shmobile/intc-sh7367.c index cc442d198cdc..cfde9bfc3669 100644 --- a/arch/arm/mach-shmobile/intc-sh7367.c +++ b/arch/arm/mach-shmobile/intc-sh7367.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -31,8 +32,6 @@ enum { DISABLED, /* interrupt sources INTCA */ - IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A, - IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A, DIRC, CRYPT1_ERR, CRYPT2_STD, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1, @@ -76,14 +75,6 @@ enum { }; static struct intc_vect intca_vectors[] __initdata = { - INTC_VECT(IRQ0A, 0x0200), INTC_VECT(IRQ1A, 0x0220), - INTC_VECT(IRQ2A, 0x0240), INTC_VECT(IRQ3A, 0x0260), - INTC_VECT(IRQ4A, 0x0280), INTC_VECT(IRQ5A, 0x02a0), - INTC_VECT(IRQ6A, 0x02c0), INTC_VECT(IRQ7A, 0x02e0), - INTC_VECT(IRQ8A, 0x0300), INTC_VECT(IRQ9A, 0x0320), - INTC_VECT(IRQ10A, 0x0340), INTC_VECT(IRQ11A, 0x0360), - INTC_VECT(IRQ12A, 0x0380), INTC_VECT(IRQ13A, 0x03a0), - INTC_VECT(IRQ14A, 0x03c0), INTC_VECT(IRQ15A, 0x03e0), INTC_VECT(DIRC, 0x0560), INTC_VECT(CRYPT1_ERR, 0x05e0), INTC_VECT(CRYPT2_STD, 0x0700), @@ -163,10 +154,6 @@ static struct intc_group intca_groups[] __initdata = { }; static struct intc_mask_reg intca_mask_registers[] __initdata = { - { 0xe6900040, 0xe6900060, 8, /* INTMSK00A / INTMSKCLR00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900044, 0xe6900064, 8, /* INTMSK10A / INTMSKCLR10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, { 0xe6940080, 0xe69400c0, 8, /* IMR0A / IMCR0A */ { DMAC2_1_DEI3, DMAC2_1_DEI2, DMAC2_1_DEI1, DMAC2_1_DEI0, ARM11_IRQPMU, 0, ARM11_COMMTX, ARM11_COMMRX } }, @@ -212,11 +199,6 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = { }; static struct intc_prio_reg intca_prio_registers[] __initdata = { - { 0xe6900010, 0, 32, 4, /* INTPRI00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900014, 0, 32, 4, /* INTPRI10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6940000, 0, 16, 4, /* IPRAA */ { DMAC3_1, DMAC3_2, CMT2, LCRC } }, { 0xe6940004, 0, 16, 4, /* IPRBA */ { IRDA, ETM11, BBIF1, BBIF2 } }, { 0xe6940008, 0, 16, 4, /* IPRCA */ { CRYPT1_ERR, CRYPT2_STD, @@ -240,29 +222,18 @@ static struct intc_prio_reg intca_prio_registers[] __initdata = { { 0xe6940038, 0, 16, 4, /* IPROA */ { 0, 0, DIRC, SDHI2 } }, }; -static struct intc_sense_reg intca_sense_registers[] __initdata = { - { 0xe6900000, 16, 2, /* ICR1A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900004, 16, 2, /* ICR2A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, -}; - -static struct intc_mask_reg intca_ack_registers[] __initdata = { - { 0xe6900020, 0, 8, /* INTREQ00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900024, 0, 8, /* INTREQ10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, -}; - static struct intc_desc intca_desc __initdata = { .name = "sh7367-intca", .force_enable = ENABLED, .force_disable = DISABLED, .hw = INTC_HW_DESC(intca_vectors, intca_groups, intca_mask_registers, intca_prio_registers, - intca_sense_registers, intca_ack_registers), + NULL, NULL), }; +INTC_IRQ_PINS_16(intca_irq_pins, 0xe6900000, + INTC_VECT, "sh7367-intca-irq-pins"); + enum { UNUSED_INTCS = 0, @@ -432,6 +403,7 @@ void __init sh7367_init_irq(void) void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); register_intc_controller(&intca_desc); + register_intc_controller(&intca_irq_pins_desc); register_intc_controller(&intcs_desc); /* demux using INTEVTSA */ From e1b3aa85b2887c06f59c9d38aa3653f797a867cb Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 Oct 2011 16:21:26 +0900 Subject: [PATCH 1418/1596] ARM: mach-shmobile: Use common INTC IRQ code on sh7377 Make use of INTC_IRQ_PINS_32() for INTCA on sh7377. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh7377.c | 67 +++------------------------- 1 file changed, 6 insertions(+), 61 deletions(-) diff --git a/arch/arm/mach-shmobile/intc-sh7377.c b/arch/arm/mach-shmobile/intc-sh7377.c index fe45154ce660..2af4e6e9bc5b 100644 --- a/arch/arm/mach-shmobile/intc-sh7377.c +++ b/arch/arm/mach-shmobile/intc-sh7377.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -31,10 +32,6 @@ enum { DISABLED, /* interrupt sources INTCA */ - IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A, - IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A, - IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A, - IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A, DIRC, _2DG, CRYPT_STD, @@ -91,22 +88,6 @@ enum { }; static struct intc_vect intca_vectors[] __initdata = { - INTC_VECT(IRQ0A, 0x0200), INTC_VECT(IRQ1A, 0x0220), - INTC_VECT(IRQ2A, 0x0240), INTC_VECT(IRQ3A, 0x0260), - INTC_VECT(IRQ4A, 0x0280), INTC_VECT(IRQ5A, 0x02a0), - INTC_VECT(IRQ6A, 0x02c0), INTC_VECT(IRQ7A, 0x02e0), - INTC_VECT(IRQ8A, 0x0300), INTC_VECT(IRQ9A, 0x0320), - INTC_VECT(IRQ10A, 0x0340), INTC_VECT(IRQ11A, 0x0360), - INTC_VECT(IRQ12A, 0x0380), INTC_VECT(IRQ13A, 0x03a0), - INTC_VECT(IRQ14A, 0x03c0), INTC_VECT(IRQ15A, 0x03e0), - INTC_VECT(IRQ16A, 0x3200), INTC_VECT(IRQ17A, 0x3220), - INTC_VECT(IRQ18A, 0x3240), INTC_VECT(IRQ19A, 0x3260), - INTC_VECT(IRQ20A, 0x3280), INTC_VECT(IRQ31A, 0x32a0), - INTC_VECT(IRQ22A, 0x32c0), INTC_VECT(IRQ23A, 0x32e0), - INTC_VECT(IRQ24A, 0x3300), INTC_VECT(IRQ25A, 0x3320), - INTC_VECT(IRQ26A, 0x3340), INTC_VECT(IRQ27A, 0x3360), - INTC_VECT(IRQ28A, 0x3380), INTC_VECT(IRQ29A, 0x33a0), - INTC_VECT(IRQ30A, 0x33c0), INTC_VECT(IRQ31A, 0x33e0), INTC_VECT(DIRC, 0x0560), INTC_VECT(_2DG, 0x05e0), INTC_VECT(CRYPT_STD, 0x0700), @@ -203,15 +184,6 @@ static struct intc_group intca_groups[] __initdata = { }; static struct intc_mask_reg intca_mask_registers[] __initdata = { - { 0xe6900040, 0xe6900060, 8, /* INTMSK00A / INTMSKCLR00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900044, 0xe6900064, 8, /* INTMSK10A / INTMSKCLR10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6900048, 0xe6900068, 8, /* INTMSK20A / INTMSKCLR20A */ - { IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A } }, - { 0xe690004c, 0xe690006c, 8, /* INTMSK30A / INTMSKCLR30A */ - { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } }, - { 0xe6940080, 0xe69400c0, 8, /* IMR0A / IMCR0A */ { DMAC2_1_DEI3, DMAC2_1_DEI2, DMAC2_1_DEI1, DMAC2_1_DEI0, AP_ARM_IRQPMU, 0, AP_ARM_COMMTX, AP_ARM_COMMRX } }, @@ -273,15 +245,6 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = { }; static struct intc_prio_reg intca_prio_registers[] __initdata = { - { 0xe6900010, 0, 32, 4, /* INTPRI00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900014, 0, 32, 4, /* INTPRI10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6900018, 0, 32, 4, /* INTPRI10A */ - { IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A } }, - { 0xe690001c, 0, 32, 4, /* INTPRI30A */ - { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } }, - { 0xe6940000, 0, 16, 4, /* IPRAA */ { DMAC3_1, DMAC3_2, CMT2, LCRC } }, { 0xe6940004, 0, 16, 4, /* IPRBA */ { IRDA, 0, BBIF1, BBIF2 } }, { 0xe6940008, 0, 16, 4, /* IPRCA */ { _2DG, CRYPT_STD, @@ -315,37 +278,18 @@ static struct intc_prio_reg intca_prio_registers[] __initdata = { { 0xe694003c, 0, 16, 4, /* IPRPA3 */ { SCIFA6, 0, 0, 0 } }, }; -static struct intc_sense_reg intca_sense_registers[] __initdata = { - { 0xe6900000, 16, 2, /* ICR1A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900004, 16, 2, /* ICR2A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6900008, 16, 2, /* ICR3A */ - { IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A } }, - { 0xe690000c, 16, 2, /* ICR4A */ - { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } }, -}; - -static struct intc_mask_reg intca_ack_registers[] __initdata = { - { 0xe6900020, 0, 8, /* INTREQ00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900024, 0, 8, /* INTREQ10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6900028, 0, 8, /* INTREQ20A */ - { IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A } }, - { 0xe690002c, 0, 8, /* INTREQ30A */ - { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } }, -}; - static struct intc_desc intca_desc __initdata = { .name = "sh7377-intca", .force_enable = ENABLED, .force_disable = DISABLED, .hw = INTC_HW_DESC(intca_vectors, intca_groups, intca_mask_registers, intca_prio_registers, - intca_sense_registers, intca_ack_registers), + NULL, NULL), }; +INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000, + INTC_VECT, "sh7377-intca-irq-pins"); + /* this macro ignore entry which is also in INTCA */ #define __IGNORE(a...) #define __IGNORE0(a...) 0 @@ -638,6 +582,7 @@ void __init sh7377_init_irq(void) void __iomem *intevtsa = ioremap_nocache(INTEVTSA, PAGE_SIZE); register_intc_controller(&intca_desc); + register_intc_controller(&intca_irq_pins_desc); register_intc_controller(&intcs_desc); /* demux using INTEVTSA */ From da5713ef03aba15761eeeade4f4938e5db98b1e2 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 Oct 2011 16:21:34 +0900 Subject: [PATCH 1419/1596] ARM: mach-shmobile: Use common INTC IRQ code on sh7372 Make use of INTC_IRQ_PINS_32() for INTCA on sh7372. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh7372.c | 72 ++++------------------------ 1 file changed, 8 insertions(+), 64 deletions(-) diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index 29cdc0522d9c..2d8856df80e2 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,10 +30,6 @@ enum { UNUSED_INTCA = 0, /* interrupt sources INTCA */ - IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A, - IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A, - IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A, - IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A, DIRC, CRYPT_STD, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1, @@ -86,22 +83,6 @@ enum { }; static struct intc_vect intca_vectors[] __initdata = { - INTC_VECT(IRQ0A, 0x0200), INTC_VECT(IRQ1A, 0x0220), - INTC_VECT(IRQ2A, 0x0240), INTC_VECT(IRQ3A, 0x0260), - INTC_VECT(IRQ4A, 0x0280), INTC_VECT(IRQ5A, 0x02a0), - INTC_VECT(IRQ6A, 0x02c0), INTC_VECT(IRQ7A, 0x02e0), - INTC_VECT(IRQ8A, 0x0300), INTC_VECT(IRQ9A, 0x0320), - INTC_VECT(IRQ10A, 0x0340), INTC_VECT(IRQ11A, 0x0360), - INTC_VECT(IRQ12A, 0x0380), INTC_VECT(IRQ13A, 0x03a0), - INTC_VECT(IRQ14A, 0x03c0), INTC_VECT(IRQ15A, 0x03e0), - INTC_VECT(IRQ16A, 0x3200), INTC_VECT(IRQ17A, 0x3220), - INTC_VECT(IRQ18A, 0x3240), INTC_VECT(IRQ19A, 0x3260), - INTC_VECT(IRQ20A, 0x3280), INTC_VECT(IRQ21A, 0x32a0), - INTC_VECT(IRQ22A, 0x32c0), INTC_VECT(IRQ23A, 0x32e0), - INTC_VECT(IRQ24A, 0x3300), INTC_VECT(IRQ25A, 0x3320), - INTC_VECT(IRQ26A, 0x3340), INTC_VECT(IRQ27A, 0x3360), - INTC_VECT(IRQ28A, 0x3380), INTC_VECT(IRQ29A, 0x33a0), - INTC_VECT(IRQ30A, 0x33c0), INTC_VECT(IRQ31A, 0x33e0), INTC_VECT(DIRC, 0x0560), INTC_VECT(CRYPT_STD, 0x0700), INTC_VECT(IIC1_ALI1, 0x0780), INTC_VECT(IIC1_TACKI1, 0x07a0), @@ -203,15 +184,6 @@ static struct intc_group intca_groups[] __initdata = { }; static struct intc_mask_reg intca_mask_registers[] __initdata = { - { 0xe6900040, 0xe6900060, 8, /* INTMSK00A / INTMSKCLR00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900044, 0xe6900064, 8, /* INTMSK10A / INTMSKCLR10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6900048, 0xe6900068, 8, /* INTMSK20A / INTMSKCLR20A */ - { IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A } }, - { 0xe690004c, 0xe690006c, 8, /* INTMSK30A / INTMSKCLR30A */ - { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } }, - { 0xe6940080, 0xe69400c0, 8, /* IMR0A / IMCR0A */ { DMAC2_1_DEI3, DMAC2_1_DEI2, DMAC2_1_DEI1, DMAC2_1_DEI0, AP_ARM_IRQPMU, 0, AP_ARM_COMMTX, AP_ARM_COMMRX } }, @@ -282,15 +254,6 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = { }; static struct intc_prio_reg intca_prio_registers[] __initdata = { - { 0xe6900010, 0, 32, 4, /* INTPRI00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900014, 0, 32, 4, /* INTPRI10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6900018, 0, 32, 4, /* INTPRI20A */ - { IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A } }, - { 0xe690001c, 0, 32, 4, /* INTPRI30A */ - { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } }, - { 0xe6940000, 0, 16, 4, /* IPRAA */ { DMAC3_1, DMAC3_2, CMT2, 0 } }, { 0xe6940004, 0, 16, 4, /* IPRBA */ { IRDA, 0, BBIF1, BBIF2 } }, { 0xe6940008, 0, 16, 4, /* IPRCA */ { 0, CRYPT_STD, @@ -336,33 +299,13 @@ static struct intc_prio_reg intca_prio_registers[] __initdata = { { 0xe6950050, 0, 16, 4, /* IPRUA3 */ { USBHSDMAC1_USHDMI, 0, 0, 0 } }, }; -static struct intc_sense_reg intca_sense_registers[] __initdata = { - { 0xe6900000, 32, 4, /* ICR1A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900004, 32, 4, /* ICR2A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6900008, 32, 4, /* ICR3A */ - { IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A } }, - { 0xe690000c, 32, 4, /* ICR4A */ - { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } }, -}; - -static struct intc_mask_reg intca_ack_registers[] __initdata = { - { 0xe6900020, 0, 8, /* INTREQ00A */ - { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, - { 0xe6900024, 0, 8, /* INTREQ10A */ - { IRQ8A, IRQ9A, IRQ10A, IRQ11A, IRQ12A, IRQ13A, IRQ14A, IRQ15A } }, - { 0xe6900028, 0, 8, /* INTREQ20A */ - { IRQ16A, IRQ17A, IRQ18A, IRQ19A, IRQ20A, IRQ21A, IRQ22A, IRQ23A } }, - { 0xe690002c, 0, 8, /* INTREQ30A */ - { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } }, -}; - -static DECLARE_INTC_DESC_ACK(intca_desc, "sh7372-intca", - intca_vectors, intca_groups, - intca_mask_registers, intca_prio_registers, - intca_sense_registers, intca_ack_registers); +static DECLARE_INTC_DESC(intca_desc, "sh7372-intca", + intca_vectors, intca_groups, + intca_mask_registers, intca_prio_registers, + NULL); +INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000, + INTC_VECT, "sh7372-intca-irq-pins"); enum { UNUSED_INTCS = 0, ENABLED_INTCS, @@ -618,6 +561,7 @@ void __init sh7372_init_irq(void) intcs_ffd5 = ioremap_nocache(0xffd50000, PAGE_SIZE); register_intc_controller(&intca_desc); + register_intc_controller(&intca_irq_pins_desc); register_intc_controller(&intcs_desc); /* demux using INTEVTSA */ From a1993055efcc14fd6d213b936d28a41ea52e1d3d Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 Oct 2011 16:21:42 +0900 Subject: [PATCH 1420/1596] ARM: mach-shmobile: Use common INTC IRQ code on sh73a0 Improve IRQ triggering support by making use of the macro INTC_IRQ_PINS_32() for INTCA on sh73a0. Unfortunately it is not as easy as just using the macro as-is, we need to do mask and unmaks in the GIC but configure other bits and ack in INTCA. Update GPIO IRQ mappings while at it. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh73a0.c | 122 +++++++++++++++++++++++++++ arch/arm/mach-shmobile/pfc-sh73a0.c | 68 +++++++-------- 2 files changed, 157 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index a911a60e7719..836e81557986 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -255,20 +256,141 @@ static int sh73a0_set_wake(struct irq_data *data, unsigned int on) return 0; /* always allow wakeup */ } +#define RELOC_BASE 0x1000 + +/* INTCA IRQ pins at INTCS + 0x1000 to make space for GIC+INTC handling */ +#define INTCS_VECT_RELOC(n, vect) INTCS_VECT((n), (vect) + RELOC_BASE) + +INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000, + INTCS_VECT_RELOC, "sh73a0-intca-irq-pins"); + +static int to_gic_irq(struct irq_data *data) +{ + unsigned int vect = irq2evt(data->irq) - INTCS_VECT_BASE; + + if (vect >= 0x3200) + vect -= 0x3000; + else + vect -= 0x0200; + + return gic_spi((vect >> 5) + 1); +} + +static int to_intca_reloc_irq(struct irq_data *data) +{ + return data->irq + (RELOC_BASE >> 5); +} + +#define irq_cb(cb, irq) irq_get_chip(irq)->cb(irq_get_irq_data(irq)) +#define irq_cbp(cb, irq, p...) irq_get_chip(irq)->cb(irq_get_irq_data(irq), p) + +static void intca_gic_enable(struct irq_data *data) +{ + irq_cb(irq_unmask, to_intca_reloc_irq(data)); + irq_cb(irq_unmask, to_gic_irq(data)); +} + +static void intca_gic_disable(struct irq_data *data) +{ + irq_cb(irq_mask, to_gic_irq(data)); + irq_cb(irq_mask, to_intca_reloc_irq(data)); +} + +static void intca_gic_mask_ack(struct irq_data *data) +{ + irq_cb(irq_mask, to_gic_irq(data)); + irq_cb(irq_mask_ack, to_intca_reloc_irq(data)); +} + +static void intca_gic_eoi(struct irq_data *data) +{ + irq_cb(irq_eoi, to_gic_irq(data)); +} + +static int intca_gic_set_type(struct irq_data *data, unsigned int type) +{ + return irq_cbp(irq_set_type, to_intca_reloc_irq(data), type); +} + +static int intca_gic_set_wake(struct irq_data *data, unsigned int on) +{ + return irq_cbp(irq_set_wake, to_intca_reloc_irq(data), on); +} + +#ifdef CONFIG_SMP +static int intca_gic_set_affinity(struct irq_data *data, + const struct cpumask *cpumask, + bool force) +{ + return irq_cbp(irq_set_affinity, to_gic_irq(data), cpumask, force); +} +#endif + +struct irq_chip intca_gic_irq_chip = { + .name = "INTCA-GIC", + .irq_mask = intca_gic_disable, + .irq_unmask = intca_gic_enable, + .irq_mask_ack = intca_gic_mask_ack, + .irq_eoi = intca_gic_eoi, + .irq_enable = intca_gic_enable, + .irq_disable = intca_gic_disable, + .irq_shutdown = intca_gic_disable, + .irq_set_type = intca_gic_set_type, + .irq_set_wake = intca_gic_set_wake, +#ifdef CONFIG_SMP + .irq_set_affinity = intca_gic_set_affinity, +#endif +}; + +static int to_intc_vect(int irq) +{ + unsigned int irq_pin = irq - gic_spi(1); + unsigned int offs; + + if (irq_pin < 16) + offs = 0x0200; + else + offs = 0x3000; + + return offs + (irq_pin << 5); +} + +static irqreturn_t sh73a0_irq_pin_demux(int irq, void *dev_id) +{ + generic_handle_irq(intcs_evt2irq(to_intc_vect(irq))); + return IRQ_HANDLED; +} + +static struct irqaction sh73a0_irq_pin_cascade[32]; + void __init sh73a0_init_irq(void) { void __iomem *gic_dist_base = __io(0xf0001000); void __iomem *gic_cpu_base = __io(0xf0000100); void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); + int k, n; gic_init(0, 29, gic_dist_base, gic_cpu_base); gic_arch_extn.irq_set_wake = sh73a0_set_wake; register_intc_controller(&intcs_desc); + register_intc_controller(&intca_irq_pins_desc); /* demux using INTEVTSA */ sh73a0_intcs_cascade.name = "INTCS cascade"; sh73a0_intcs_cascade.handler = sh73a0_intcs_demux; sh73a0_intcs_cascade.dev_id = intevtsa; setup_irq(gic_spi(50), &sh73a0_intcs_cascade); + + /* IRQ pins require special handling through INTCA and GIC */ + for (k = 0; k < 32; k++) { + sh73a0_irq_pin_cascade[k].name = "INTCA-GIC cascade"; + sh73a0_irq_pin_cascade[k].handler = sh73a0_irq_pin_demux; + setup_irq(gic_spi(1 + k), &sh73a0_irq_pin_cascade[k]); + + n = intcs_evt2irq(to_intc_vect(gic_spi(1 + k))); + irq_set_chip_and_handler_name(n, &intca_gic_irq_chip, + handle_level_irq, "level"); + set_irq_flags(n, IRQF_VALID); /* yuck */ + } } diff --git a/arch/arm/mach-shmobile/pfc-sh73a0.c b/arch/arm/mach-shmobile/pfc-sh73a0.c index 57322c9fd9b6..5abe02fbd6b9 100644 --- a/arch/arm/mach-shmobile/pfc-sh73a0.c +++ b/arch/arm/mach-shmobile/pfc-sh73a0.c @@ -2766,41 +2766,43 @@ static struct pinmux_data_reg pinmux_data_regs[] = { { }, }; -#define EXT_IRQ(n) gic_spi((n) + 1) /* GIC SPI starting from 1 for IRQ0 */ +/* IRQ pins through INTCS with IRQ0->15 from 0x200 and IRQ16-31 from 0x3200 */ +#define EXT_IRQ16L(n) intcs_evt2irq(0x200 + ((n) << 5)) +#define EXT_IRQ16H(n) intcs_evt2irq(0x3200 + ((n - 16) << 5)) static struct pinmux_irq pinmux_irqs[] = { - PINMUX_IRQ(EXT_IRQ(19), PORT9_FN0), - PINMUX_IRQ(EXT_IRQ(1), PORT10_FN0), - PINMUX_IRQ(EXT_IRQ(0), PORT11_FN0), - PINMUX_IRQ(EXT_IRQ(18), PORT13_FN0), - PINMUX_IRQ(EXT_IRQ(20), PORT14_FN0), - PINMUX_IRQ(EXT_IRQ(21), PORT15_FN0), - PINMUX_IRQ(EXT_IRQ(31), PORT26_FN0), - PINMUX_IRQ(EXT_IRQ(30), PORT27_FN0), - PINMUX_IRQ(EXT_IRQ(29), PORT28_FN0), - PINMUX_IRQ(EXT_IRQ(22), PORT40_FN0), - PINMUX_IRQ(EXT_IRQ(23), PORT53_FN0), - PINMUX_IRQ(EXT_IRQ(10), PORT54_FN0), - PINMUX_IRQ(EXT_IRQ(9), PORT56_FN0), - PINMUX_IRQ(EXT_IRQ(26), PORT115_FN0), - PINMUX_IRQ(EXT_IRQ(27), PORT116_FN0), - PINMUX_IRQ(EXT_IRQ(28), PORT117_FN0), - PINMUX_IRQ(EXT_IRQ(24), PORT118_FN0), - PINMUX_IRQ(EXT_IRQ(6), PORT147_FN0), - PINMUX_IRQ(EXT_IRQ(2), PORT149_FN0), - PINMUX_IRQ(EXT_IRQ(7), PORT150_FN0), - PINMUX_IRQ(EXT_IRQ(12), PORT156_FN0), - PINMUX_IRQ(EXT_IRQ(4), PORT159_FN0), - PINMUX_IRQ(EXT_IRQ(25), PORT164_FN0), - PINMUX_IRQ(EXT_IRQ(8), PORT223_FN0), - PINMUX_IRQ(EXT_IRQ(3), PORT224_FN0), - PINMUX_IRQ(EXT_IRQ(5), PORT227_FN0), - PINMUX_IRQ(EXT_IRQ(17), PORT234_FN0), - PINMUX_IRQ(EXT_IRQ(11), PORT238_FN0), - PINMUX_IRQ(EXT_IRQ(13), PORT239_FN0), - PINMUX_IRQ(EXT_IRQ(16), PORT249_FN0), - PINMUX_IRQ(EXT_IRQ(14), PORT251_FN0), - PINMUX_IRQ(EXT_IRQ(9), PORT308_FN0), + PINMUX_IRQ(EXT_IRQ16H(19), PORT9_FN0), + PINMUX_IRQ(EXT_IRQ16L(1), PORT10_FN0), + PINMUX_IRQ(EXT_IRQ16L(0), PORT11_FN0), + PINMUX_IRQ(EXT_IRQ16H(18), PORT13_FN0), + PINMUX_IRQ(EXT_IRQ16H(20), PORT14_FN0), + PINMUX_IRQ(EXT_IRQ16H(21), PORT15_FN0), + PINMUX_IRQ(EXT_IRQ16H(31), PORT26_FN0), + PINMUX_IRQ(EXT_IRQ16H(30), PORT27_FN0), + PINMUX_IRQ(EXT_IRQ16H(29), PORT28_FN0), + PINMUX_IRQ(EXT_IRQ16H(22), PORT40_FN0), + PINMUX_IRQ(EXT_IRQ16H(23), PORT53_FN0), + PINMUX_IRQ(EXT_IRQ16L(10), PORT54_FN0), + PINMUX_IRQ(EXT_IRQ16L(9), PORT56_FN0), + PINMUX_IRQ(EXT_IRQ16H(26), PORT115_FN0), + PINMUX_IRQ(EXT_IRQ16H(27), PORT116_FN0), + PINMUX_IRQ(EXT_IRQ16H(28), PORT117_FN0), + PINMUX_IRQ(EXT_IRQ16H(24), PORT118_FN0), + PINMUX_IRQ(EXT_IRQ16L(6), PORT147_FN0), + PINMUX_IRQ(EXT_IRQ16L(2), PORT149_FN0), + PINMUX_IRQ(EXT_IRQ16L(7), PORT150_FN0), + PINMUX_IRQ(EXT_IRQ16L(12), PORT156_FN0), + PINMUX_IRQ(EXT_IRQ16L(4), PORT159_FN0), + PINMUX_IRQ(EXT_IRQ16H(25), PORT164_FN0), + PINMUX_IRQ(EXT_IRQ16L(8), PORT223_FN0), + PINMUX_IRQ(EXT_IRQ16L(3), PORT224_FN0), + PINMUX_IRQ(EXT_IRQ16L(5), PORT227_FN0), + PINMUX_IRQ(EXT_IRQ16H(17), PORT234_FN0), + PINMUX_IRQ(EXT_IRQ16L(11), PORT238_FN0), + PINMUX_IRQ(EXT_IRQ16L(13), PORT239_FN0), + PINMUX_IRQ(EXT_IRQ16H(16), PORT249_FN0), + PINMUX_IRQ(EXT_IRQ16L(14), PORT251_FN0), + PINMUX_IRQ(EXT_IRQ16L(9), PORT308_FN0), }; static struct pinmux_info sh73a0_pinmux_info = { From 3087b905c4050afeb1847fb0fcf89b3e09f6ffee Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 Oct 2011 16:21:50 +0900 Subject: [PATCH 1421/1596] ARM: mach-shmobile: SDHI0 GPIO hotplug for AG5EVM Implement GPIO hotplugging via TMIO_MMC_HAS_COLD_CD for AG5EVM SDHI0. This is possible now when INTCA is used for IRQ triggering on sh73a0. Without INTCA IRQ support we are left with the GIC hardware block that does not support dealing with active low interrupt sources. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ag5evm.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 475342bcc95c..d6e461710524 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -339,6 +339,18 @@ static struct platform_device mipidsi0_device = { }, }; +/* SDHI0 */ +static irqreturn_t ag5evm_sdhi0_gpio_cd(int irq, void *arg) +{ + struct device *dev = arg; + struct sh_mobile_sdhi_info *info = dev->platform_data; + struct tmio_mmc_data *pdata = info->pdata; + + tmio_mmc_cd_wakeup(pdata); + + return IRQ_HANDLED; +} + static struct sh_mobile_sdhi_info sdhi0_info = { .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, @@ -570,6 +582,13 @@ static void __init ag5evm_init(void) gpio_request(GPIO_FN_SDHID0_1, NULL); gpio_request(GPIO_FN_SDHID0_0, NULL); + if (!request_irq(intcs_evt2irq(0x3c0), ag5evm_sdhi0_gpio_cd, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "sdhi0 cd", &sdhi0_device.dev)) + sdhi0_info.tmio_flags |= TMIO_MMC_HAS_COLD_CD; + else + pr_warn("Unable to setup SDHI0 GPIO IRQ\n"); + /* enable SDHI1 on CN4 [WLAN I/F] */ gpio_request(GPIO_FN_SDHICLK1, NULL); gpio_request(GPIO_FN_SDHICMD1_PU, NULL); From 91c088ae17c62f7741d9563e36935bc7a69a7e9e Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 17 Oct 2011 18:00:35 +0900 Subject: [PATCH 1422/1596] ARM: mach-shmobile: Add support for PINT though INTC macros Add a INTC_PINT() macro with various helper bits to allow SoCs like sh73a0 to suppor the PINT hardware using regular INTC tables. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/include/mach/intc.h | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm/mach-shmobile/include/mach/intc.h b/arch/arm/mach-shmobile/include/mach/intc.h index 1cd8b36678ee..8b22258c8caa 100644 --- a/arch/arm/mach-shmobile/include/mach/intc.h +++ b/arch/arm/mach-shmobile/include/mach/intc.h @@ -192,4 +192,55 @@ static struct intc_desc p ## _desc __initdata = { \ p ## _sense_registers, p ## _ack_registers) \ } +#define INTC_PINT_E_EMPTY +#define INTC_PINT_E_NONE 0, 0, 0, 0, 0, 0, 0, 0, +#define INTC_PINT_E(p) \ + PINT ## p ## 0, PINT ## p ## 1, PINT ## p ## 2, PINT ## p ## 3, \ + PINT ## p ## 4, PINT ## p ## 5, PINT ## p ## 6, PINT ## p ## 7, + +#define INTC_PINT_V_NONE +#define INTC_PINT_V(p, vect) \ + vect(PINT ## p ## 0, 0), vect(PINT ## p ## 1, 1), \ + vect(PINT ## p ## 2, 2), vect(PINT ## p ## 3, 3), \ + vect(PINT ## p ## 4, 4), vect(PINT ## p ## 5, 5), \ + vect(PINT ## p ## 6, 6), vect(PINT ## p ## 7, 7), + +#define INTC_PINT(p, mask_reg, sense_base, str, \ + enums_1, enums_2, enums_3, enums_4, \ + vect_1, vect_2, vect_3, vect_4, \ + mask_a, mask_b, mask_c, mask_d, \ + sense_a, sense_b, sense_c, sense_d) \ + \ +enum { \ + PINT ## p ## _UNUSED = 0, \ + enums_1 enums_2 enums_3 enums_4 \ +}; \ + \ +static struct intc_vect p ## _vectors[] __initdata = { \ + vect_1 vect_2 vect_3 vect_4 \ +}; \ + \ +static struct intc_mask_reg p ## _mask_registers[] __initdata = { \ + { mask_reg, 0, 32, /* PINTER */ \ + { mask_a mask_b mask_c mask_d } } \ +}; \ + \ +static struct intc_sense_reg p ## _sense_registers[] __initdata = { \ + { sense_base + 0x00, 16, 2, /* PINTCR */ \ + { sense_a } }, \ + { sense_base + 0x04, 16, 2, /* PINTCR */ \ + { sense_b } }, \ + { sense_base + 0x08, 16, 2, /* PINTCR */ \ + { sense_c } }, \ + { sense_base + 0x0c, 16, 2, /* PINTCR */ \ + { sense_d } }, \ +}; \ + \ +static struct intc_desc p ## _desc __initdata = { \ + .name = str, \ + .hw = INTC_HW_DESC(p ## _vectors, NULL, \ + p ## _mask_registers, NULL, \ + p ## _sense_registers, NULL), \ +} + #endif /* __ASM_MACH_INTC_H */ From 566aad39df77211467078e0b3dcd62100f56b5e4 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 17 Oct 2011 18:00:52 +0900 Subject: [PATCH 1423/1596] ARM: mach-shmobile: sh73a0 and AG5EVM PINT support Support PINT on sh73a0 and AG5EVM using INTC PINT macros. With this patch applied the AG5EVM ethernet is handled through one of the chained sh73a0 PINT interrupt controllers. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ag5evm.c | 17 +---- arch/arm/mach-shmobile/include/mach/sh73a0.h | 4 ++ arch/arm/mach-shmobile/intc-sh73a0.c | 65 ++++++++++++++++++++ 3 files changed, 71 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index d6e461710524..83624e26b884 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -59,7 +59,7 @@ static struct resource smsc9220_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(33), /* PINT1 */ + .start = SH73A0_PINT0_IRQ(2), /* PINTA2 */ .flags = IORESOURCE_IRQ, }, }; @@ -474,19 +474,6 @@ static void __init ag5evm_map_io(void) shmobile_setup_console(); } -#define PINTC_ADDR 0xe6900000 -#define PINTER0A (PINTC_ADDR + 0xa0) -#define PINTCR0A (PINTC_ADDR + 0xb0) - -void __init ag5evm_init_irq(void) -{ - sh73a0_init_irq(); - - /* setup PINT: enable PINTA2 as active low */ - __raw_writel(__raw_readl(PINTER0A) | (1<<29), PINTER0A); - __raw_writew(__raw_readw(PINTCR0A) | (2<<10), PINTCR0A); -} - #define DSI0PHYCR 0xe615006c static void __init ag5evm_init(void) @@ -620,7 +607,7 @@ struct sys_timer ag5evm_timer = { MACHINE_START(AG5EVM, "ag5evm") .map_io = ag5evm_map_io, - .init_irq = ag5evm_init_irq, + .init_irq = sh73a0_init_irq, .handle_irq = shmobile_handle_irq_gic, .init_machine = ag5evm_init, .timer = &ag5evm_timer, diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h index b385e976797a..18ae6a990bc2 100644 --- a/arch/arm/mach-shmobile/include/mach/sh73a0.h +++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h @@ -507,4 +507,8 @@ enum { SHDMA_SLAVE_MMCIF_RX, }; +/* PINT interrupts are located at Linux IRQ 768 and up */ +#define SH73A0_PINT0_IRQ(irq) ((irq) + 768) +#define SH73A0_PINT1_IRQ(irq) ((irq) + 800) + #endif /* __ASM_SH73A0_H__ */ diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index 836e81557986..1eda6b0b69e3 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -363,6 +364,59 @@ static irqreturn_t sh73a0_irq_pin_demux(int irq, void *dev_id) static struct irqaction sh73a0_irq_pin_cascade[32]; +#define PINTER0 0xe69000a0 +#define PINTER1 0xe69000a4 +#define PINTRR0 0xe69000d0 +#define PINTRR1 0xe69000d4 + +#define PINT0A_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq)) +#define PINT0B_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq + 8)) +#define PINT0C_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq + 16)) +#define PINT0D_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq + 24)) +#define PINT1E_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT1_IRQ(irq)) + +INTC_PINT(intc_pint0, PINTER0, 0xe69000b0, "sh73a0-pint0", \ + INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D), \ + INTC_PINT_V(A, PINT0A_IRQ), INTC_PINT_V(B, PINT0B_IRQ), \ + INTC_PINT_V(C, PINT0C_IRQ), INTC_PINT_V(D, PINT0D_IRQ), \ + INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D), \ + INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D)); + +INTC_PINT(intc_pint1, PINTER1, 0xe69000c0, "sh73a0-pint1", \ + INTC_PINT_E(E), INTC_PINT_E_EMPTY, INTC_PINT_E_EMPTY, INTC_PINT_E_EMPTY, \ + INTC_PINT_V(E, PINT1E_IRQ), INTC_PINT_V_NONE, \ + INTC_PINT_V_NONE, INTC_PINT_V_NONE, \ + INTC_PINT_E_NONE, INTC_PINT_E_NONE, INTC_PINT_E_NONE, INTC_PINT_E(E), \ + INTC_PINT_E(E), INTC_PINT_E_NONE, INTC_PINT_E_NONE, INTC_PINT_E_NONE); + +static struct irqaction sh73a0_pint0_cascade; +static struct irqaction sh73a0_pint1_cascade; + +static void pint_demux(unsigned long rr, unsigned long er, int base_irq) +{ + unsigned long value = ioread32(rr) & ioread32(er); + int k; + + for (k = 0; k < 32; k++) { + if (value & (1 << (31 - k))) { + generic_handle_irq(base_irq + k); + iowrite32(~(1 << (31 - k)), rr); + } + } +} + +static irqreturn_t sh73a0_pint0_demux(int irq, void *dev_id) +{ + pint_demux(PINTRR0, PINTER0, SH73A0_PINT0_IRQ(0)); + return IRQ_HANDLED; +} + +static irqreturn_t sh73a0_pint1_demux(int irq, void *dev_id) +{ + pint_demux(PINTRR1, PINTER1, SH73A0_PINT1_IRQ(0)); + return IRQ_HANDLED; +} + void __init sh73a0_init_irq(void) { void __iomem *gic_dist_base = __io(0xf0001000); @@ -375,6 +429,8 @@ void __init sh73a0_init_irq(void) register_intc_controller(&intcs_desc); register_intc_controller(&intca_irq_pins_desc); + register_intc_controller(&intc_pint0_desc); + register_intc_controller(&intc_pint1_desc); /* demux using INTEVTSA */ sh73a0_intcs_cascade.name = "INTCS cascade"; @@ -393,4 +449,13 @@ void __init sh73a0_init_irq(void) handle_level_irq, "level"); set_irq_flags(n, IRQF_VALID); /* yuck */ } + + /* PINT pins are sanely tied to the GIC as SPI */ + sh73a0_pint0_cascade.name = "PINT0 cascade"; + sh73a0_pint0_cascade.handler = sh73a0_pint0_demux; + setup_irq(gic_spi(33), &sh73a0_pint0_cascade); + + sh73a0_pint1_cascade.name = "PINT1 cascade"; + sh73a0_pint1_cascade.handler = sh73a0_pint1_demux; + setup_irq(gic_spi(34), &sh73a0_pint1_cascade); } From 99f8bd8556ad829e042e66c1b25a35f1bcc38981 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 30 Aug 2011 16:19:13 +0000 Subject: [PATCH 1424/1596] ARM: mach-shmobile: ag5evm needs CONFIG_I2C ag5evm implements a backlight control, using an I2C controller, therefore it needs CONFIG_I2C to fix this make failure arch/arm/mach-shmobile/built-in.o: In function `lcd_on': pfc-sh73a0.c:(.text+0x2334): undefined reference to `i2c_get_adapter' pfc-sh73a0.c:(.text+0x2370): undefined reference to `i2c_transfer' (ignore pfc-sh73a0.c) and to build successfully. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index c1b45342e1fb..0828fab2b65c 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -26,6 +26,7 @@ config ARCH_SH73A0 select SH_CLK_CPG select ARCH_WANT_OPTIONAL_GPIOLIB select ARM_GIC + select I2C comment "SH-Mobile Board Type" From 2c4ce609347f2a45792c8d9ebb5af11217766cb6 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Fri, 4 Nov 2011 00:19:46 +0200 Subject: [PATCH 1425/1596] IB/iser: Use separate buffers for the login request/response The driver counted on the transactional nature of iSCSI login/text flows and used the same buffer for both the request and the response. We also went further and did DMA mapping only once, with DMA_FROM_DEVICE, which violates the DMA mapping API. Fix that by using different buffers, one for requests and one for responses, and use the correct DMA mapping direction for each. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 3 +- drivers/infiniband/ulp/iser/iser_initiator.c | 31 +++++++++++++----- drivers/infiniband/ulp/iser/iser_verbs.c | 33 +++++++++++++++----- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index db6f3ce9f3bf..2982a14a0557 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -257,7 +257,8 @@ struct iser_conn { struct list_head conn_list; /* entry in ig conn list */ char *login_buf; - u64 login_dma; + char *login_req_buf, *login_resp_buf; + u64 login_req_dma, login_resp_dma; unsigned int rx_desc_head; struct iser_rx_desc *rx_descs; struct ib_recv_wr rx_wr[ISER_MIN_POSTED_RX]; diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index f299de6b419b..a607542fc796 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -221,8 +221,14 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn) struct iser_device *device = ib_conn->device; if (ib_conn->login_buf) { - ib_dma_unmap_single(device->ib_device, ib_conn->login_dma, - ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE); + if (ib_conn->login_req_dma) + ib_dma_unmap_single(device->ib_device, + ib_conn->login_req_dma, + ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE); + if (ib_conn->login_resp_dma) + ib_dma_unmap_single(device->ib_device, + ib_conn->login_resp_dma, + ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE); kfree(ib_conn->login_buf); } @@ -394,6 +400,7 @@ int iser_send_control(struct iscsi_conn *conn, unsigned long data_seg_len; int err = 0; struct iser_device *device; + struct iser_conn *ib_conn = iser_conn->ib_conn; /* build the tx desc regd header and add it to the tx desc dto */ mdesc->type = ISCSI_TX_CONTROL; @@ -409,9 +416,19 @@ int iser_send_control(struct iscsi_conn *conn, iser_err("data present on non login task!!!\n"); goto send_control_error; } - memcpy(iser_conn->ib_conn->login_buf, task->data, + + ib_dma_sync_single_for_cpu(device->ib_device, + ib_conn->login_req_dma, task->data_count, + DMA_TO_DEVICE); + + memcpy(iser_conn->ib_conn->login_req_buf, task->data, task->data_count); - tx_dsg->addr = iser_conn->ib_conn->login_dma; + + ib_dma_sync_single_for_device(device->ib_device, + ib_conn->login_req_dma, task->data_count, + DMA_TO_DEVICE); + + tx_dsg->addr = iser_conn->ib_conn->login_req_dma; tx_dsg->length = task->data_count; tx_dsg->lkey = device->mr->lkey; mdesc->num_sge = 2; @@ -445,8 +462,8 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc, int rx_buflen, outstanding, count, err; /* differentiate between login to all other PDUs */ - if ((char *)rx_desc == ib_conn->login_buf) { - rx_dma = ib_conn->login_dma; + if ((char *)rx_desc == ib_conn->login_resp_buf) { + rx_dma = ib_conn->login_resp_dma; rx_buflen = ISER_RX_LOGIN_SIZE; } else { rx_dma = rx_desc->dma_addr; @@ -473,7 +490,7 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc, * for the posted rx bufs refcount to become zero handles everything */ conn->ib_conn->post_recv_buf_count--; - if (rx_dma == ib_conn->login_dma) + if (rx_dma == ib_conn->login_resp_dma) return; outstanding = ib_conn->post_recv_buf_count; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index ede1475bee09..e28877c4ce15 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -155,20 +155,39 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) { struct iser_device *device; struct ib_qp_init_attr init_attr; - int ret = -ENOMEM; + int req_err, resp_err, ret = -ENOMEM; struct ib_fmr_pool_param params; BUG_ON(ib_conn->device == NULL); device = ib_conn->device; - ib_conn->login_buf = kmalloc(ISER_RX_LOGIN_SIZE, GFP_KERNEL); + ib_conn->login_buf = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN + + ISER_RX_LOGIN_SIZE, GFP_KERNEL); if (!ib_conn->login_buf) goto out_err; - ib_conn->login_dma = ib_dma_map_single(ib_conn->device->ib_device, - (void *)ib_conn->login_buf, ISER_RX_LOGIN_SIZE, - DMA_FROM_DEVICE); + ib_conn->login_req_buf = ib_conn->login_buf; + ib_conn->login_resp_buf = ib_conn->login_buf + ISCSI_DEF_MAX_RECV_SEG_LEN; + + ib_conn->login_req_dma = ib_dma_map_single(ib_conn->device->ib_device, + (void *)ib_conn->login_req_buf, + ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE); + + ib_conn->login_resp_dma = ib_dma_map_single(ib_conn->device->ib_device, + (void *)ib_conn->login_resp_buf, + ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE); + + req_err = ib_dma_mapping_error(device->ib_device, ib_conn->login_req_dma); + resp_err = ib_dma_mapping_error(device->ib_device, ib_conn->login_resp_dma); + + if (req_err || resp_err) { + if (req_err) + ib_conn->login_req_dma = 0; + if (resp_err) + ib_conn->login_resp_dma = 0; + goto out_err; + } ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) + (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)), @@ -658,11 +677,11 @@ int iser_post_recvl(struct iser_conn *ib_conn) struct ib_sge sge; int ib_ret; - sge.addr = ib_conn->login_dma; + sge.addr = ib_conn->login_resp_dma; sge.length = ISER_RX_LOGIN_SIZE; sge.lkey = ib_conn->device->mr->lkey; - rx_wr.wr_id = (unsigned long)ib_conn->login_buf; + rx_wr.wr_id = (unsigned long)ib_conn->login_resp_buf; rx_wr.sg_list = &sge; rx_wr.num_sge = 1; rx_wr.next = NULL; From 52439540ea30396982b69662dd21aede6b336288 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Fri, 4 Nov 2011 00:21:27 +0200 Subject: [PATCH 1426/1596] IB/iser: DMA unmap TX bufs used for iSCSI/iSER headers The current driver never does DMA unmapping on these buffers. Fix that by adding DMA unmapping to the task cleanup callback, and DMA mapping to the task init function (drop the headers_initialized micro-optimization). Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.c | 11 ++++++++--- drivers/infiniband/ulp/iser/iscsi_iser.h | 1 - 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 84e8c293a715..c42b8f390c0b 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -151,7 +151,6 @@ int iser_initialize_task_headers(struct iscsi_task *task, tx_desc->tx_sg[0].length = ISER_HEADERS_LEN; tx_desc->tx_sg[0].lkey = device->mr->lkey; - iser_task->headers_initialized = 1; iser_task->iser_conn = iser_conn; return 0; } @@ -166,8 +165,7 @@ iscsi_iser_task_init(struct iscsi_task *task) { struct iscsi_iser_task *iser_task = task->dd_data; - if (!iser_task->headers_initialized) - if (iser_initialize_task_headers(task, &iser_task->desc)) + if (iser_initialize_task_headers(task, &iser_task->desc)) return -ENOMEM; /* mgmt task */ @@ -278,6 +276,13 @@ iscsi_iser_task_xmit(struct iscsi_task *task) static void iscsi_iser_cleanup_task(struct iscsi_task *task) { struct iscsi_iser_task *iser_task = task->dd_data; + struct iser_tx_desc *tx_desc = &iser_task->desc; + + struct iscsi_iser_conn *iser_conn = task->conn->dd_data; + struct iser_device *device = iser_conn->ib_conn->device; + + ib_dma_unmap_single(device->ib_device, + tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); /* mgmt tasks do not need special cleanup */ if (!task->sc) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 2982a14a0557..db7ea3704da7 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -278,7 +278,6 @@ struct iscsi_iser_task { struct iser_regd_buf rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */ struct iser_data_buf data[ISER_DIRS_NUM]; /* orig. data des*/ struct iser_data_buf data_copy[ISER_DIRS_NUM];/* contig. copy */ - int headers_initialized; }; struct iser_page_vec { From 30ab7e230b996f750d4fc24b6bf8214e83effa12 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Fri, 4 Nov 2011 08:26:52 -0400 Subject: [PATCH 1427/1596] IB/qib: Fix panic in RC error flushing logic The following panic can occur when flushing a QP: RIP: 0010:[] [] qib_send_complete+0x3b/0x190 [ib_qib] RSP: 0018:ffff8803cdc6fc90 EFLAGS: 00010046 RAX: 0000000000000000 RBX: ffff8803d84ba000 RCX: 0000000000000000 RDX: 0000000000000005 RSI: ffffc90015a53430 RDI: ffff8803d84ba000 RBP: ffff8803cdc6fce0 R08: ffff8803cdc6fc90 R09: 0000000000000001 R10: 00000000ffffffff R11: 0000000000000000 R12: ffff8803d84ba0c0 R13: ffff8803d84ba5cc R14: 0000000000000800 R15: 0000000000000246 FS: 0000000000000000(0000) GS:ffff880036600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 0000000000000034 CR3: 00000003e44f9000 CR4: 00000000000406f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process qib/0 (pid: 1350, threadinfo ffff8803cdc6e000, task ffff88042728a100) Stack: 53544c5553455201 0000000100000005 0000000000000000 ffff8803d84ba000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000001 ffff8803cdc6fd30 ffffffffa0165d7a Call Trace: [] qib_make_rc_req+0x36a/0xe80 [ib_qib] [] ? qib_make_rc_req+0x0/0xe80 [ib_qib] [] qib_do_send+0xf3/0xb60 [ib_qib] [] ? thread_return+0x4e/0x777 [] ? qib_do_send+0x0/0xb60 [ib_qib] [] worker_thread+0x170/0x2a0 [] ? autoremove_wake_function+0x0/0x40 [] ? worker_thread+0x0/0x2a0 [] kthread+0x96/0xa0 [] child_rip+0xa/0x20 [] ? kthread+0x0/0xa0 [] ? child_rip+0x0/0x20 RIP [] qib_send_complete+0x3b/0x190 [ib_qib] The RC error state flush logic in qib_make_rc_req() could return all of the acked wqes and potentially have emptied the queue. It would then unconditionally try return a flush completion via qib_send_complete() for an invalid wqe, or worse a valid one that is not queued. The panic results when the completion code tries to maintain an MR reference count for a NULL MR. This fix modifies logic to only send one completion per qib_make_rc_req() call and changing the completion status from IB_WC_SUCCESS to IB_WC_WR_FLUSH_ERR as the completions progress. The outer loop will call as many times as necessary to flush the queue. Reviewed-by: Ram Vepa Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_rc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index afaf4ac79f42..894afac26f3b 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -271,13 +271,9 @@ int qib_make_rc_req(struct qib_qp *qp) goto bail; } wqe = get_swqe_ptr(qp, qp->s_last); - while (qp->s_last != qp->s_acked) { - qib_send_complete(qp, wqe, IB_WC_SUCCESS); - if (++qp->s_last >= qp->s_size) - qp->s_last = 0; - wqe = get_swqe_ptr(qp, qp->s_last); - } - qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); + qib_send_complete(qp, wqe, qp->s_last != qp->s_acked ? + IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR); + /* will get called again */ goto done; } From 54d5026e7c173edae8a27c293c286f1783d21ae8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 4 Nov 2011 18:07:43 +0100 Subject: [PATCH 1428/1596] mac80211: warn only once about not finding a rate The warning really shouldn't happen, but until we find the reason why it does don't spew it all the time, just once is enough to know we've hit it. Reported-by: Linus Torvalds Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index dc1123aa8181..72eddd1b410b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3567,8 +3567,9 @@ rate_lowest_index(struct ieee80211_supported_band *sband, return i; /* warn when we cannot find a rate. */ - WARN_ON(1); + WARN_ON_ONCE(1); + /* and return 0 (the lowest index) */ return 0; } From 5fe69d7e258a17d825d982ac695c1db5c4bc4768 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 4 Nov 2011 11:22:05 -0700 Subject: [PATCH 1429/1596] Documentation: update cgroups notes - ns cgroup has been removed. - it's true moving a task to another cgroup can fail. Signed-off-by: Li Zefan Acked-by: Paul Menage Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/cgroups/cgroups.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index cd67e90003c0..9c452ef2328c 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt @@ -454,8 +454,8 @@ mounted hierarchy, to remove a task from its current cgroup you must move it into a new cgroup (possibly the root cgroup) by writing to the new cgroup's tasks file. -Note: If the ns cgroup is active, moving a process to another cgroup can -fail. +Note: Due to some restrictions enforced by some cgroup subsystems, moving +a process to another cgroup can fail. 2.3 Mounting hierarchies by name -------------------------------- From 123aeec2ff5f749e92f8e3dd2d42f7a9948ca037 Mon Sep 17 00:00:00 2001 From: Kumar Appaiah Date: Fri, 4 Nov 2011 11:22:09 -0700 Subject: [PATCH 1430/1596] Documentation: thinkpad-acpi grammo fixes This adds minor grammatical fixes to the description of the keys in the thinkpad-acpi documentation. Signed-off-by: Kumar Appaiah Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/laptops/thinkpad-acpi.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 3ff0dad62d36..9d666828915a 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -411,9 +411,9 @@ event code Key Notes 0x1004 0x03 FN+F4 Sleep button (ACPI sleep button semantics, i.e. sleep-to-RAM). - It is always generate some kind + It always generates some kind of event, either the hot key - event or a ACPI sleep button + event or an ACPI sleep button event. The firmware may refuse to generate further FN+F4 key presses until a S3 or S4 ACPI From d83fe6b6c54749a9b2d3198d62ec981024459425 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Fri, 4 Nov 2011 11:22:14 -0700 Subject: [PATCH 1431/1596] Documentation: fix inotify source file paths Fixes the path to find the source files of the inotify subsystem. Signed-off-by: Marcos Paulo de Souza Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/filesystems/inotify.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/filesystems/inotify.txt b/Documentation/filesystems/inotify.txt index 59a919f16144..cfd02712b83e 100644 --- a/Documentation/filesystems/inotify.txt +++ b/Documentation/filesystems/inotify.txt @@ -194,7 +194,8 @@ associated with the inotify_handle, and on which events are queued. Each watch is associated with an inotify_watch structure. Watches are chained off of each associated inotify_handle and each associated inode. -See fs/inotify.c and fs/inotify_user.c for the locking and lifetime rules. +See fs/notify/inotify/inotify_fsnotify.c and fs/notify/inotify/inotify_user.c +for the locking and lifetime rules. (vi) Rationale From b218ab0a5af943441e1daa7dc811874ecd409229 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Fri, 4 Nov 2011 11:22:19 -0700 Subject: [PATCH 1432/1596] Documentation: update CodingStyle use of braces After commit 38829dc9d7b4 ("Documentation/CodingStyle: flesh out if-else examples") highlight that if _only_one_ branch of a conditional statement is a single statement, then braces are to be used on both branches. Signed-off-by: Antonio Ospite Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/CodingStyle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index c940239d9678..2b90d328b3ba 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -166,8 +166,8 @@ if (condition) else do_that(); -This does not apply if one branch of a conditional statement is a single -statement. Use braces in both branches. +This does not apply if only one branch of a conditional statement is a single +statement; in the latter case use braces in both branches: if (condition) { do_this(); From ab05210bcba83b1fe2702eac7d4d453a97855c26 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Fri, 4 Nov 2011 11:22:22 -0700 Subject: [PATCH 1433/1596] Documentation: HFS is orphaned Removed the reference of Roman Zippel, last maintainer, of orphaned HFS filesystem. Signed-off-by: Marcos Paulo de Souza Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/filesystems/hfs.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Documentation/filesystems/hfs.txt b/Documentation/filesystems/hfs.txt index bd0fa7704035..d096df6db07a 100644 --- a/Documentation/filesystems/hfs.txt +++ b/Documentation/filesystems/hfs.txt @@ -1,3 +1,4 @@ +Note: This filesystem doesn't have a maintainer. Macintosh HFS Filesystem for Linux ================================== @@ -76,8 +77,6 @@ hformat that can be used to create HFS filesystem. See Credits ======= -The HFS drivers was written by Paul H. Hargrovea (hargrove@sccm.Stanford.EDU) -and is now maintained by Roman Zippel (roman@ardistech.com) at Ardis -Technologies. -Roman rewrote large parts of the code and brought in btree routines derived -from Brad Boyer's hfsplus driver (also maintained by Roman now). +The HFS drivers was written by Paul H. Hargrovea (hargrove@sccm.Stanford.EDU). +Roman Zippel (roman@ardistech.com) rewrote large parts of the code and brought +in btree routines derived from Brad Boyer's hfsplus driver. From b670722009d52c79aea8ff7ed561365ee21ff58c Mon Sep 17 00:00:00 2001 From: Marcos Paulo Souza Date: Fri, 4 Nov 2011 11:22:26 -0700 Subject: [PATCH 1434/1596] Documentation: Computone ip2 is orphaned Removed the email for support and fixes for orphaned ip2 driver. Signed-off-by: Marcos Paulo de Souza Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/serial/computone.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/serial/computone.txt b/Documentation/serial/computone.txt index 60a6f657c37d..39ddcdbeeb85 100644 --- a/Documentation/serial/computone.txt +++ b/Documentation/serial/computone.txt @@ -20,8 +20,6 @@ Version: 1.2.14 Date: 11/01/2001 Historical Author: Andrew Manison Primary Author: Doug McNash -Support: support@computone.com -Fixes and Updates: Mike Warfield This file assumes that you are using the Computone drivers which are integrated into the kernel sources. For updating the drivers or installing From ee31892aaf47f1b5fd1323c9397db5d3f22d8b9e Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Fri, 4 Nov 2011 11:22:29 -0700 Subject: [PATCH 1435/1596] Documentation: fix leds-class.txt duplicated word Fix a typo (duplicated word) in Documentation/leds/leds-class.txt Signed-off-by: Bryan Wu Acked-by: Richard Purdie Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/leds/leds-class.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/leds/leds-class.txt b/Documentation/leds/leds-class.txt index 4996586e27e8..79699c200766 100644 --- a/Documentation/leds/leds-class.txt +++ b/Documentation/leds/leds-class.txt @@ -61,8 +61,8 @@ Hardware accelerated blink of LEDs Some LEDs can be programmed to blink without any CPU interaction. To support this feature, a LED driver can optionally implement the blink_set() function (see ). To set an LED to blinking, -however, it is better to use use the API function led_blink_set(), -as it will check and implement software fallback if necessary. +however, it is better to use the API function led_blink_set(), as it +will check and implement software fallback if necessary. To turn off blinking again, use the API function led_brightness_set() as that will not just set the LED brightness but also stop any software From b31966816dcd3d8b16109f39d7c7501dc9abb010 Mon Sep 17 00:00:00 2001 From: Wang Sheng-Hui Date: Fri, 4 Nov 2011 11:22:33 -0700 Subject: [PATCH 1436/1596] Documentation: drop as block elevator reference in switching-sched.txt Remove 'as' for as is no longer supported, and we can not use 'elevator=as' any more. Signed-off-by: Wang Sheng-Hui Signed-off-by: Randy Dunlap Cc: Jens Axboe Signed-off-by: Linus Torvalds --- Documentation/block/switching-sched.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/block/switching-sched.txt b/Documentation/block/switching-sched.txt index 71cfbdc0f74d..3b2612e342f1 100644 --- a/Documentation/block/switching-sched.txt +++ b/Documentation/block/switching-sched.txt @@ -1,6 +1,6 @@ To choose IO schedulers at boot time, use the argument 'elevator=deadline'. -'noop', 'as' and 'cfq' (the default) are also available. IO schedulers are -assigned globally at boot time only presently. +'noop' and 'cfq' (the default) are also available. IO schedulers are assigned +globally at boot time only presently. Each io queue has a set of io scheduler tunables associated with it. These tunables control how the io scheduler works. You can find these entries From ddf6ce45a7b1193f3cf20ad234f35af3b998b8f8 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 3 Nov 2011 00:58:59 +0100 Subject: [PATCH 1437/1596] ACPI / PM: Add Sony VPCEB17FX to nonvs blacklist Another entry for the nonvs blacklist, as noted by a user in https://bugzilla.redhat.com/show_bug.cgi?id=641789#c12 Signed-off-by: Dave Jones Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 0e46faef1d30..6d9a3ab58db2 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -398,6 +398,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, { .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB17FX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), + }, + }, + { + .callback = init_nvs_nosave, .ident = "Sony Vaio VGN-SR11M", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), From 79cfbdfa87e84992d509e6c1648a18e1d7e68c20 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Thu, 3 Nov 2011 00:59:25 +0100 Subject: [PATCH 1438/1596] PM / Sleep: Fix race between CPU hotplug and freezer The CPU hotplug notifications sent out by the _cpu_up() and _cpu_down() functions depend on the value of the 'tasks_frozen' argument passed to them (which indicates whether tasks have been frozen or not). (Examples for such CPU hotplug notifications: CPU_ONLINE, CPU_ONLINE_FROZEN, CPU_DEAD, CPU_DEAD_FROZEN). Thus, it is essential that while the callbacks for those notifications are running, the state of the system with respect to the tasks being frozen or not remains unchanged, *throughout that duration*. Hence there is a need for synchronizing the CPU hotplug code with the freezer subsystem. Since the freezer is involved only in the Suspend/Hibernate call paths, this patch hooks the CPU hotplug code to the suspend/hibernate notifiers PM_[SUSPEND|HIBERNATE]_PREPARE and PM_POST_[SUSPEND|HIBERNATE] to prevent the race between CPU hotplug and freezer, thus ensuring that CPU hotplug notifications will always be run with the state of the system really being what the notifications indicate, _throughout_ their execution time. Signed-off-by: Srivatsa S. Bhat Signed-off-by: Rafael J. Wysocki --- kernel/cpu.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/kernel/cpu.c b/kernel/cpu.c index 12b7458f23b1..aa39dd7a3846 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_SMP /* Serializes the updates to cpu_online_mask, cpu_present_mask */ @@ -476,6 +477,79 @@ static int alloc_frozen_cpus(void) return 0; } core_initcall(alloc_frozen_cpus); + +/* + * Prevent regular CPU hotplug from racing with the freezer, by disabling CPU + * hotplug when tasks are about to be frozen. Also, don't allow the freezer + * to continue until any currently running CPU hotplug operation gets + * completed. + * To modify the 'cpu_hotplug_disabled' flag, we need to acquire the + * 'cpu_add_remove_lock'. And this same lock is also taken by the regular + * CPU hotplug path and released only after it is complete. Thus, we + * (and hence the freezer) will block here until any currently running CPU + * hotplug operation gets completed. + */ +void cpu_hotplug_disable_before_freeze(void) +{ + cpu_maps_update_begin(); + cpu_hotplug_disabled = 1; + cpu_maps_update_done(); +} + + +/* + * When tasks have been thawed, re-enable regular CPU hotplug (which had been + * disabled while beginning to freeze tasks). + */ +void cpu_hotplug_enable_after_thaw(void) +{ + cpu_maps_update_begin(); + cpu_hotplug_disabled = 0; + cpu_maps_update_done(); +} + +/* + * When callbacks for CPU hotplug notifications are being executed, we must + * ensure that the state of the system with respect to the tasks being frozen + * or not, as reported by the notification, remains unchanged *throughout the + * duration* of the execution of the callbacks. + * Hence we need to prevent the freezer from racing with regular CPU hotplug. + * + * This synchronization is implemented by mutually excluding regular CPU + * hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/ + * Hibernate notifications. + */ +static int +cpu_hotplug_pm_callback(struct notifier_block *nb, + unsigned long action, void *ptr) +{ + switch (action) { + + case PM_SUSPEND_PREPARE: + case PM_HIBERNATION_PREPARE: + cpu_hotplug_disable_before_freeze(); + break; + + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + cpu_hotplug_enable_after_thaw(); + break; + + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + + +int cpu_hotplug_pm_sync_init(void) +{ + pm_notifier(cpu_hotplug_pm_callback, 0); + return 0; +} +core_initcall(cpu_hotplug_pm_sync_init); + #endif /* CONFIG_PM_SLEEP_SMP */ /** From 4e71c9545b9afaa47f178b7ffda0bc630c8ad2c7 Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Thu, 3 Nov 2011 00:59:40 +0100 Subject: [PATCH 1439/1596] PM / Sleep: Remove unused symbol 'suspend_cpu_hotplug' Remove the suspend_cpu_hotplug declaration, which doesn't correspond to an existing variable. [rjw: Added the changelog.] Signed-off-by: Srivatsa S. Bhat Signed-off-by: Rafael J. Wysocki --- include/linux/cpu.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/linux/cpu.h b/include/linux/cpu.h index b1a635acf72a..6cb60fd2ea84 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -196,13 +196,9 @@ static inline void cpu_hotplug_driver_unlock(void) #endif /* CONFIG_HOTPLUG_CPU */ #ifdef CONFIG_PM_SLEEP_SMP -extern int suspend_cpu_hotplug; - extern int disable_nonboot_cpus(void); extern void enable_nonboot_cpus(void); #else /* !CONFIG_PM_SLEEP_SMP */ -#define suspend_cpu_hotplug 0 - static inline int disable_nonboot_cpus(void) { return 0; } static inline void enable_nonboot_cpus(void) {} #endif /* !CONFIG_PM_SLEEP_SMP */ From e9db50b839c592fcd22952d7f1dccbd0a56da57d Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Thu, 3 Nov 2011 00:59:52 +0100 Subject: [PATCH 1440/1596] PM / Sleep: Update freezer documentation This patch: * Substitutes some obsolete references to kernel/power/process.c by kernel/freezer.c. * Mentions kernel/freezer.c as being part of the "freezer" code along with the rest of the files. * Fixes a trivial typo. Signed-off-by: Srivatsa S. Bhat Signed-off-by: Rafael J. Wysocki --- Documentation/power/freezing-of-tasks.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/power/freezing-of-tasks.txt b/Documentation/power/freezing-of-tasks.txt index 38b57248fd61..316c2ba187f4 100644 --- a/Documentation/power/freezing-of-tasks.txt +++ b/Documentation/power/freezing-of-tasks.txt @@ -22,12 +22,12 @@ try_to_freeze_tasks() that sets TIF_FREEZE for all of the freezable tasks and either wakes them up, if they are kernel threads, or sends fake signals to them, if they are user space processes. A task that has TIF_FREEZE set, should react to it by calling the function called refrigerator() (defined in -kernel/power/process.c), which sets the task's PF_FROZEN flag, changes its state +kernel/freezer.c), which sets the task's PF_FROZEN flag, changes its state to TASK_UNINTERRUPTIBLE and makes it loop until PF_FROZEN is cleared for it. Then, we say that the task is 'frozen' and therefore the set of functions handling this mechanism is referred to as 'the freezer' (these functions are -defined in kernel/power/process.c and include/linux/freezer.h). User space -processes are generally frozen before kernel threads. +defined in kernel/power/process.c, kernel/freezer.c & include/linux/freezer.h). +User space processes are generally frozen before kernel threads. It is not recommended to call refrigerator() directly. Instead, it is recommended to use the try_to_freeze() function (defined in @@ -95,7 +95,7 @@ after the memory for the image has been freed, we don't want tasks to allocate additional memory and we prevent them from doing that by freezing them earlier. [Of course, this also means that device drivers should not allocate substantial amounts of memory from their .suspend() callbacks before hibernation, but this -is e separate issue.] +is a separate issue.] 3. The third reason is to prevent user space processes and some kernel threads from interfering with the suspending and resuming of devices. A user space From def0c0a37d02820497fcd5a74b6cc93dbce5dc06 Mon Sep 17 00:00:00 2001 From: venu byravarasu Date: Thu, 3 Nov 2011 10:12:14 +0100 Subject: [PATCH 1441/1596] PM / Runtime: Fix runtime accounting calculation error With delta type being int, its value is made zero for all values of now > 0x80000000. Hence fixing it. Signed-off-by: venu byravarasu Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 6bb3aafa85ed..18ef87e525fa 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -29,13 +29,10 @@ static int rpm_suspend(struct device *dev, int rpmflags); void update_pm_runtime_accounting(struct device *dev) { unsigned long now = jiffies; - int delta; + unsigned long delta; delta = now - dev->power.accounting_timestamp; - if (delta < 0) - delta = 0; - dev->power.accounting_timestamp = now; if (dev->power.disable_depth > 0) From a96d69d1b02c4a526bd8c07e0cb10c129025c88c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 3 Nov 2011 10:12:27 +0100 Subject: [PATCH 1442/1596] PM / OPP: Fix build when CONFIG_PM_OPP is not set Commit 03ca370fbf7b76d6d002380dbdc2cdc2319f9c80 (PM / OPP: Add OPP availability change notifier) does not compile if CONFIG_PM_OPP is not set: arch/arm/plat-omap/omap-pm-noop.o: In function `opp_get_notifier': include/linux/opp.h:103: multiple definition of `opp_get_notifier' include/linux/opp.h:103: first defined here Also fix incorrect comment. Signed-off-by: Tony Lindgren Signed-off-by: Rafael J. Wysocki --- include/linux/opp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/opp.h b/include/linux/opp.h index 87a9208f8aec..ee94b33080c2 100644 --- a/include/linux/opp.h +++ b/include/linux/opp.h @@ -97,11 +97,11 @@ static inline int opp_disable(struct device *dev, unsigned long freq) return 0; } -struct srcu_notifier_head *opp_get_notifier(struct device *dev) +static inline struct srcu_notifier_head *opp_get_notifier(struct device *dev) { return ERR_PTR(-EINVAL); } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_OPP */ #if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP) int opp_init_cpufreq_table(struct device *dev, From 6513fd6972f725291ee8ce62c7a39fb8a6c7391e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 3 Nov 2011 10:12:36 +0100 Subject: [PATCH 1443/1596] PM / QoS: Remove redundant check Remove an "if" check, that repeats an equivalent one 6 lines above. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Rafael J. Wysocki --- kernel/power/qos.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 1c1797dd1d1d..5167d996cd02 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -386,8 +386,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp) pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE); filp->private_data = req; - if (filp->private_data) - return 0; + return 0; } return -EPERM; } From 886486b792e4f6f96d4fbe8ec5bf20811cab7d6a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 3 Nov 2011 23:39:18 +0100 Subject: [PATCH 1444/1596] PM / Runtime: Automatically retry failed autosuspends Originally, the runtime PM core would send an idle notification whenever a suspend attempt failed. The idle callback routine could then schedule a delayed suspend for some time later. However this behavior was changed by commit f71648d73c1650b8b4aceb3856bebbde6daa3b86 (PM / Runtime: Remove idle notification after failing suspend). No notifications were sent, and there was no clear mechanism to retry failed suspends. This caused problems for the usbhid driver, because it fails autosuspend attempts as long as a key is being held down. Therefore this patch (as1492) adds a mechanism for retrying failed autosuspends. If the callback routine updates the last_busy field so that the next autosuspend expiration time is in the future, the autosuspend will automatically be rescheduled. Signed-off-by: Alan Stern Tested-by: Henrik Rydberg Cc: Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.txt | 10 ++++++++++ drivers/base/power/runtime.c | 18 ++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 0e856088db7c..5336149f831b 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -789,6 +789,16 @@ will behave normally, not taking the autosuspend delay into account. Similarly, if the power.use_autosuspend field isn't set then the autosuspend helper functions will behave just like the non-autosuspend counterparts. +Under some circumstances a driver or subsystem may want to prevent a device +from autosuspending immediately, even though the usage counter is zero and the +autosuspend delay time has expired. If the ->runtime_suspend() callback +returns -EAGAIN or -EBUSY, and if the next autosuspend delay expiration time is +in the future (as it normally would be if the callback invoked +pm_runtime_mark_last_busy()), the PM core will automatically reschedule the +autosuspend. The ->runtime_suspend() callback can't do this rescheduling +itself because no suspend requests of any kind are accepted while the device is +suspending (i.e., while the callback is running). + The implementation is well suited for asynchronous use in interrupt contexts. However such use inevitably involves races, because the PM core can't synchronize ->runtime_suspend() callbacks with the arrival of I/O requests. diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 18ef87e525fa..124dbf60c9bf 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -293,6 +293,9 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) * the callback was running then carry it out, otherwise send an idle * notification for its parent (if the suspend succeeded and both * ignore_children of parent->power and irq_safe of dev->power are not set). + * If ->runtime_suspend failed with -EAGAIN or -EBUSY, and if the RPM_AUTO + * flag is set and the next autosuspend-delay expiration time is in the + * future, schedule another autosuspend attempt. * * This function must be called under dev->power.lock with interrupts disabled. */ @@ -413,10 +416,21 @@ static int rpm_suspend(struct device *dev, int rpmflags) if (retval) { __update_runtime_status(dev, RPM_ACTIVE); dev->power.deferred_resume = false; - if (retval == -EAGAIN || retval == -EBUSY) + if (retval == -EAGAIN || retval == -EBUSY) { dev->power.runtime_error = 0; - else + + /* + * If the callback routine failed an autosuspend, and + * if the last_busy time has been updated so that there + * is a new autosuspend expiration time, automatically + * reschedule another autosuspend. + */ + if ((rpmflags & RPM_AUTO) && + pm_runtime_autosuspend_expiration(dev) != 0) + goto repeat; + } else { pm_runtime_cancel_pending(dev); + } wake_up_all(&dev->power.wait_queue); goto out; } From b2c0a863e14676fa5760c6d828fd373288e2f64a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 4 Nov 2011 00:52:46 +0100 Subject: [PATCH 1445/1596] USB: Update last_busy time after autosuspend fails Originally, the runtime PM core would send an idle notification whenever a suspend attempt failed. The idle callback routine could then schedule a delayed suspend for some time later. However this behavior was changed by commit f71648d73c1650b8b4aceb3856bebbde6daa3b86 (PM / Runtime: Remove idle notification after failing suspend). No notifications were sent, and there was no clear mechanism to retry failed suspends. This caused problems for the usbhid driver, because it fails autosuspend attempts as long as a key is being held down. A companion patch changes the PM core's behavior, but we also need to change the USB core. In particular, this patch (as1493) updates the device's last_busy time when an autosuspend fails, so that the PM core will retry the autosuspend in the future when the delay time expires again. Signed-off-by: Alan Stern Tested-by: Henrik Rydberg Cc: Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/usb/core/driver.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 3b029a0a4787..c2c0ae57e7ff 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1667,6 +1667,11 @@ int usb_runtime_suspend(struct device *dev) return -EAGAIN; status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); + + /* Allow a retry if autosuspend failed temporarily */ + if (status == -EAGAIN || status == -EBUSY) + usb_mark_last_busy(udev); + /* The PM core reacts badly unless the return code is 0, * -EAGAIN, or -EBUSY, so always return -EBUSY on an error. */ From 6f35c4abd7f0294166a5e0ab0401fe7949b33034 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 3 Nov 2011 16:07:49 -0700 Subject: [PATCH 1446/1596] PM / Freezer: Reimplement wait_event_freezekillable using freezer_do_not_count/freezer_count Commit 27920651fe "PM / Freezer: Make fake_signal_wake_up() wake TASK_KILLABLE tasks too" updated fake_signal_wake_up() used by freezer to wake up KILLABLE tasks. Sending unsolicited wakeups to tasks in killable sleep is dangerous as there are code paths which depend on tasks not waking up spuriously from KILLABLE sleep. For example. sys_read() or page can sleep in TASK_KILLABLE assuming that wait/down/whatever _killable can only fail if we can not return to the usermode. TASK_TRACED is another obvious example. The offending commit was to resolve freezer hang during system PM operations caused by KILLABLE sleeps in network filesystems. wait_event_freezekillable(), which depends on the spurious KILLABLE wakeup, was added by f06ac72e92 "cifs, freezer: add wait_event_freezekillable and have cifs use it" to be used to implement killable & freezable sleeps in network filesystems. To prepare for reverting of 27920651fe, this patch reimplements wait_event_freezekillable() using freezer_do_not_count/freezer_count() so that it doesn't depend on the spurious KILLABLE wakeup. This isn't very nice but should do for now. [tj: Refreshed patch to apply to linus/master and updated commit description on Rafael's request.] Signed-off-by: Oleg Nesterov Signed-off-by: Tejun Heo Signed-off-by: Rafael J. Wysocki --- include/linux/freezer.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/include/linux/freezer.h b/include/linux/freezer.h index a49b52934c55..a5386e3ee756 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -143,14 +143,9 @@ static inline void set_freezable_with_signal(void) #define wait_event_freezekillable(wq, condition) \ ({ \ int __retval; \ - do { \ - __retval = wait_event_killable(wq, \ - (condition) || freezing(current)); \ - if (__retval && !freezing(current)) \ - break; \ - else if (!(condition)) \ - __retval = -ERESTARTSYS; \ - } while (try_to_freeze()); \ + freezer_do_not_count(); \ + __retval = wait_event_killable(wq, (condition)); \ + freezer_count(); \ __retval; \ }) From d6cc76856d353a3a9c43bead33210b9216dce332 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 4 Nov 2011 01:04:52 +0100 Subject: [PATCH 1447/1596] PM / Freezer: Revert 27920651fe "PM / Freezer: Make fake_signal_wake_up() wake TASK_KILLABLE tasks too" Commit 27920651fe "PM / Freezer: Make fake_signal_wake_up() wake TASK_KILLABLE tasks too" updated fake_signal_wake_up() used by freezer to wake up KILLABLE tasks. Sending unsolicited wakeups to tasks in killable sleep is dangerous as there are code paths which depend on tasks not waking up spuriously from KILLABLE sleep. For example. sys_read() or page can sleep in TASK_KILLABLE assuming that wait/down/whatever _killable can only fail if we can not return to the usermode. TASK_TRACED is another obvious example. The previous patch updated wait_event_freezekillable() such that it doesn't depend on the spurious wakeup. This patch reverts the offending commit. Note that the spurious KILLABLE wakeup had other implicit effects in KILLABLE sleeps in nfs and cifs and those will need further updates to regain freezekillable behavior. Signed-off-by: Tejun Heo Signed-off-by: Rafael J. Wysocki --- kernel/freezer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/freezer.c b/kernel/freezer.c index 66a594e8ad2f..7b01de98bb6a 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c @@ -67,7 +67,7 @@ static void fake_signal_wake_up(struct task_struct *p) unsigned long flags; spin_lock_irqsave(&p->sighand->siglock, flags); - signal_wake_up(p, 1); + signal_wake_up(p, 0); spin_unlock_irqrestore(&p->sighand->siglock, flags); } From 78f94dc7b10d98cf4cf8498d98581500d910c6b7 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 4 Nov 2011 09:14:58 +0000 Subject: [PATCH 1448/1596] tg3: Fix APE mutex init and use APE mutex register blocks are shared by all ports of multiport devices. For some mutexing purposes, each function is assigned their own register. For other cases, each function is assigned its own request and grant bits of a single register. For the latter cases, the tg3 driver is incorrectly allowing each function to use the same set of grant / request bits. This patch fixes the code so that each function uses the appropriate bitset. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 44 +++++++++++++++-------------- drivers/net/ethernet/broadcom/tg3.h | 10 +++++-- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 161cbbb4814a..35901630a65c 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -628,19 +628,23 @@ static void tg3_ape_lock_init(struct tg3 *tp) regbase = TG3_APE_PER_LOCK_GRANT; /* Make sure the driver hasn't any stale locks. */ - for (i = 0; i < 8; i++) { - if (i == TG3_APE_LOCK_GPIO) - continue; - tg3_ape_write32(tp, regbase + 4 * i, APE_LOCK_GRANT_DRIVER); + for (i = TG3_APE_LOCK_PHY0; i <= TG3_APE_LOCK_GPIO; i++) { + switch (i) { + case TG3_APE_LOCK_PHY0: + case TG3_APE_LOCK_PHY1: + case TG3_APE_LOCK_PHY2: + case TG3_APE_LOCK_PHY3: + bit = APE_LOCK_GRANT_DRIVER; + break; + default: + if (!tp->pci_fn) + bit = APE_LOCK_GRANT_DRIVER; + else + bit = 1 << tp->pci_fn; + } + tg3_ape_write32(tp, regbase + 4 * i, bit); } - /* Clear the correct bit of the GPIO lock too. */ - if (!tp->pci_fn) - bit = APE_LOCK_GRANT_DRIVER; - else - bit = 1 << tp->pci_fn; - - tg3_ape_write32(tp, regbase + 4 * TG3_APE_LOCK_GPIO, bit); } static int tg3_ape_lock(struct tg3 *tp, int locknum) @@ -658,6 +662,10 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum) return 0; case TG3_APE_LOCK_GRC: case TG3_APE_LOCK_MEM: + if (!tp->pci_fn) + bit = APE_LOCK_REQ_DRIVER; + else + bit = 1 << tp->pci_fn; break; default: return -EINVAL; @@ -673,11 +681,6 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum) off = 4 * locknum; - if (locknum != TG3_APE_LOCK_GPIO || !tp->pci_fn) - bit = APE_LOCK_REQ_DRIVER; - else - bit = 1 << tp->pci_fn; - tg3_ape_write32(tp, req + off, bit); /* Wait for up to 1 millisecond to acquire lock. */ @@ -710,6 +713,10 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum) return; case TG3_APE_LOCK_GRC: case TG3_APE_LOCK_MEM: + if (!tp->pci_fn) + bit = APE_LOCK_GRANT_DRIVER; + else + bit = 1 << tp->pci_fn; break; default: return; @@ -720,11 +727,6 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum) else gnt = TG3_APE_PER_LOCK_GRANT; - if (locknum != TG3_APE_LOCK_GPIO || !tp->pci_fn) - bit = APE_LOCK_GRANT_DRIVER; - else - bit = 1 << tp->pci_fn; - tg3_ape_write32(tp, gnt + 4 * locknum, bit); } diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index f32f288134c7..03fab8cadd86 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -2344,9 +2344,13 @@ #define APE_PER_LOCK_GRANT_DRIVER 0x00001000 /* APE convenience enumerations. */ -#define TG3_APE_LOCK_GRC 1 -#define TG3_APE_LOCK_MEM 4 -#define TG3_APE_LOCK_GPIO 7 +#define TG3_APE_LOCK_PHY0 0 +#define TG3_APE_LOCK_GRC 1 +#define TG3_APE_LOCK_PHY1 2 +#define TG3_APE_LOCK_PHY2 3 +#define TG3_APE_LOCK_MEM 4 +#define TG3_APE_LOCK_PHY3 5 +#define TG3_APE_LOCK_GPIO 7 #define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10 From b9e454826f22e17d1945bd282834c87aef8d0f95 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 4 Nov 2011 09:14:59 +0000 Subject: [PATCH 1449/1596] tg3: Fix 4k tx bd segmentation code The new 4k tx bd segmentation code had a bug in the error cleanup path. If the driver did not map all the physical fragments, the abort path would wind up advancing the producer index beyond the point where the setup code stopped. This would ultimately turn into a tx recovery error where the driver would expect the skb pointer to be set when it isn't. This patch fixes the problem, and then makes the code a little easier to understand. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 47 +++++++++++++++-------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 35901630a65c..507b73b979fe 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6444,31 +6444,26 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget, hwbug = 1; if (tg3_flag(tp, 4K_FIFO_LIMIT)) { + u32 prvidx = *entry; u32 tmp_flag = flags & ~TXD_FLAG_END; - while (len > TG3_TX_BD_DMA_MAX) { + while (len > TG3_TX_BD_DMA_MAX && *budget) { u32 frag_len = TG3_TX_BD_DMA_MAX; len -= TG3_TX_BD_DMA_MAX; - if (len) { - tnapi->tx_buffers[*entry].fragmented = true; - /* Avoid the 8byte DMA problem */ - if (len <= 8) { - len += TG3_TX_BD_DMA_MAX / 2; - frag_len = TG3_TX_BD_DMA_MAX / 2; - } - } else - tmp_flag = flags; - - if (*budget) { - tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, - frag_len, tmp_flag, mss, vlan); - (*budget)--; - *entry = NEXT_TX(*entry); - } else { - hwbug = 1; - break; + /* Avoid the 8byte DMA problem */ + if (len <= 8) { + len += TG3_TX_BD_DMA_MAX / 2; + frag_len = TG3_TX_BD_DMA_MAX / 2; } + tnapi->tx_buffers[*entry].fragmented = true; + + tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, + frag_len, tmp_flag, mss, vlan); + *budget -= 1; + prvidx = *entry; + *entry = NEXT_TX(*entry); + map += frag_len; } @@ -6476,10 +6471,11 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget, if (*budget) { tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, len, flags, mss, vlan); - (*budget)--; + *budget -= 1; *entry = NEXT_TX(*entry); } else { hwbug = 1; + tnapi->tx_buffers[prvidx].fragmented = false; } } } else { @@ -6561,6 +6557,8 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, dev_kfree_skb(new_skb); ret = -1; } else { + u32 save_entry = *entry; + base_flags |= TXD_FLAG_END; tnapi->tx_buffers[*entry].skb = new_skb; @@ -6570,7 +6568,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, if (tg3_tx_frag_set(tnapi, entry, budget, new_addr, new_skb->len, base_flags, mss, vlan)) { - tg3_tx_skb_unmap(tnapi, *entry, 0); + tg3_tx_skb_unmap(tnapi, save_entry, 0); dev_kfree_skb(new_skb); ret = -1; } @@ -6786,11 +6784,14 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (dma_mapping_error(&tp->pdev->dev, mapping)) goto dma_error; - if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping, + if (!budget || + tg3_tx_frag_set(tnapi, &entry, &budget, mapping, len, base_flags | ((i == last) ? TXD_FLAG_END : 0), - tmp_mss, vlan)) + tmp_mss, vlan)) { would_hit_hwbug = 1; + break; + } } } From ba1142e4fb291c7bf124d93596351dca8d226a0f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 4 Nov 2011 09:15:00 +0000 Subject: [PATCH 1450/1596] tg3: Fix 4k skb error recovery path On the error recovery resource unwind path, it is possible for the driver to attempt to unmap a fragment that hadn't been mapped. This patch fixes the problem by correcting the "last" parameter supplied. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 507b73b979fe..3a7517910eed 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6507,7 +6507,7 @@ static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last) txb = &tnapi->tx_buffers[entry]; } - for (i = 0; i < last; i++) { + for (i = 0; i <= last; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; entry = NEXT_TX(entry); @@ -6568,7 +6568,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, if (tg3_tx_frag_set(tnapi, entry, budget, new_addr, new_skb->len, base_flags, mss, vlan)) { - tg3_tx_skb_unmap(tnapi, save_entry, 0); + tg3_tx_skb_unmap(tnapi, save_entry, -1); dev_kfree_skb(new_skb); ret = -1; } @@ -6758,11 +6758,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping, len, base_flags | ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0), - mss, vlan)) + mss, vlan)) { would_hit_hwbug = 1; - /* Now loop through additional data fragments, and queue them. */ - if (skb_shinfo(skb)->nr_frags > 0) { + } else if (skb_shinfo(skb)->nr_frags > 0) { u32 tmp_mss = mss; if (!tg3_flag(tp, HW_TSO_1) && @@ -6831,7 +6830,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; dma_error: - tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i); + tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i); tnapi->tx_buffers[tnapi->tx_prod].skb = NULL; drop: dev_kfree_skb(skb); @@ -7284,7 +7283,8 @@ static void tg3_free_rings(struct tg3 *tp) if (!skb) continue; - tg3_tx_skb_unmap(tnapi, i, skb_shinfo(skb)->nr_frags); + tg3_tx_skb_unmap(tnapi, i, + skb_shinfo(skb)->nr_frags - 1); dev_kfree_skb_any(skb); } @@ -11523,7 +11523,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback) break; } - tg3_tx_skb_unmap(tnapi, tnapi->tx_prod - 1, 0); + tg3_tx_skb_unmap(tnapi, tnapi->tx_prod - 1, -1); dev_kfree_skb(skb); if (tx_idx != tnapi->tx_prod) From 5bc09186deba2a016b60aa3923fc0e42838ce877 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 4 Nov 2011 09:15:01 +0000 Subject: [PATCH 1451/1596] tg3: Fix irq alloc error cleanup path This patch fixes a bug where the irq error cleanup path did not free all the resources it allocated. Signed-off-by: Matt Carlson Signed-off-by: Ben Li Signed-off-by: Akinobu Mita Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 3a7517910eed..0413e1e85641 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -9677,15 +9677,14 @@ static int tg3_open(struct net_device *dev) struct tg3_napi *tnapi = &tp->napi[i]; err = tg3_request_irq(tp, i); if (err) { - for (i--; i >= 0; i--) + for (i--; i >= 0; i--) { + tnapi = &tp->napi[i]; free_irq(tnapi->irq_vec, tnapi); - break; + } + goto err_out2; } } - if (err) - goto err_out2; - tg3_full_lock(tp, 0); err = tg3_init_hw(tp, 1); From 9dc5e342703948ea7b086d063c85c0e79dac8149 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 4 Nov 2011 09:15:02 +0000 Subject: [PATCH 1452/1596] tg3: Obtain PCI function number from device This patch adds code to attempt to obtain the PCI function number from the device rather than accept the number handed by the kernel. In pass-through scenarios, the function number handed by the kernel may not reflect the true function of the device. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 30 +++++++++++++++++++++++------ drivers/net/ethernet/broadcom/tg3.h | 9 +++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 0413e1e85641..6973d01ae85a 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -14230,12 +14230,30 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) val = tr32(MEMARB_MODE); tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE); - if (tg3_flag(tp, PCIX_MODE)) { - pci_read_config_dword(tp->pdev, - tp->pcix_cap + PCI_X_STATUS, &val); - tp->pci_fn = val & 0x7; - } else { - tp->pci_fn = PCI_FUNC(tp->pdev->devfn) & 3; + tp->pci_fn = PCI_FUNC(tp->pdev->devfn) & 3; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + tg3_flag(tp, 5780_CLASS)) { + if (tg3_flag(tp, PCIX_MODE)) { + pci_read_config_dword(tp->pdev, + tp->pcix_cap + PCI_X_STATUS, + &val); + tp->pci_fn = val & 0x7; + } + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val); + if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) == + NIC_SRAM_CPMUSTAT_SIG) { + tp->pci_fn = val & TG3_CPMU_STATUS_FMSK_5717; + tp->pci_fn = tp->pci_fn ? 1 : 0; + } + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val); + if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) == + NIC_SRAM_CPMUSTAT_SIG) { + tp->pci_fn = (val & TG3_CPMU_STATUS_FMSK_5719) >> + TG3_CPMU_STATUS_FSHFT_5719; + } } /* Get eeprom hw config before calling tg3_set_power_state(). diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 03fab8cadd86..acfa265733ad 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -1095,6 +1095,11 @@ #define TG3_CPMU_CLCK_ORIDE 0x00003624 #define CPMU_CLCK_ORIDE_MAC_ORIDE_EN 0x80000000 +#define TG3_CPMU_STATUS 0x0000362c +#define TG3_CPMU_STATUS_FMSK_5717 0x20000000 +#define TG3_CPMU_STATUS_FMSK_5719 0xc0000000 +#define TG3_CPMU_STATUS_FSHFT_5719 30 + #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 #define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 @@ -2128,6 +2133,10 @@ #define NIC_SRAM_RGMII_EXT_IBND_RX_EN 0x00000008 #define NIC_SRAM_RGMII_EXT_IBND_TX_EN 0x00000010 +#define NIC_SRAM_CPMU_STATUS 0x00000e00 +#define NIC_SRAM_CPMUSTAT_SIG 0x0000362c +#define NIC_SRAM_CPMUSTAT_SIG_MSK 0x0000ffff + #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 #define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000 From db21997379906fe7657d360674e1106d80b020a4 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 4 Nov 2011 09:15:03 +0000 Subject: [PATCH 1453/1596] tg3: Schedule at most one tg3_reset_task run It is possible for multiple threads in the tg3 driver to each attempt to schedule a run of tg3_reset_task(). The multiple tg3_reset_task executions could all wind up on the same queue (and execute serially) or wind up on the queues of another processor (which could execute in parallel). Either scenario is not what was truly desired. This patch adds a new flag, TG3_FLAG_RESET_TASK_PENDING, and uses it to determine whether or not to schedule another run of tg3_reset_task(). With the new flag comes two new functions to facilitate scheduling and descheduling of tg3_reset_task(). Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 33 +++++++++++++++++++++-------- drivers/net/ethernet/broadcom/tg3.h | 1 + 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 6973d01ae85a..d4a85b795344 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -5929,6 +5929,18 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) return work_done; } +static inline void tg3_reset_task_schedule(struct tg3 *tp) +{ + if (!test_and_set_bit(TG3_FLAG_RESET_TASK_PENDING, tp->tg3_flags)) + schedule_work(&tp->reset_task); +} + +static inline void tg3_reset_task_cancel(struct tg3 *tp) +{ + cancel_work_sync(&tp->reset_task); + tg3_flag_clear(tp, RESET_TASK_PENDING); +} + static int tg3_poll_msix(struct napi_struct *napi, int budget) { struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); @@ -5969,7 +5981,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) tx_recovery: /* work_done is guaranteed to be less than budget. */ napi_complete(napi); - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); return work_done; } @@ -6004,7 +6016,7 @@ static void tg3_process_error(struct tg3 *tp) tg3_dump_state(tp); tg3_flag_set(tp, ERROR_PROCESSED); - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); } static int tg3_poll(struct napi_struct *napi, int budget) @@ -6051,7 +6063,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) tx_recovery: /* work_done is guaranteed to be less than budget. */ napi_complete(napi); - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); return work_done; } @@ -6345,6 +6357,7 @@ static void tg3_reset_task(struct work_struct *work) tg3_full_lock(tp, 0); if (!netif_running(tp->dev)) { + tg3_flag_clear(tp, RESET_TASK_PENDING); tg3_full_unlock(tp); return; } @@ -6382,6 +6395,8 @@ static void tg3_reset_task(struct work_struct *work) if (!err) tg3_phy_start(tp); + + tg3_flag_clear(tp, RESET_TASK_PENDING); } static void tg3_tx_timeout(struct net_device *dev) @@ -6393,7 +6408,7 @@ static void tg3_tx_timeout(struct net_device *dev) tg3_dump_state(tp); } - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); } /* Test for DMA buffers crossing any 4GB boundaries: 4G, 8G, etc */ @@ -9228,7 +9243,7 @@ static void tg3_timer(unsigned long __opaque) if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { tg3_flag_set(tp, RESTART_TIMER); spin_unlock(&tp->lock); - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); return; } } @@ -9785,7 +9800,7 @@ static int tg3_close(struct net_device *dev) struct tg3 *tp = netdev_priv(dev); tg3_napi_disable(tp); - cancel_work_sync(&tp->reset_task); + tg3_reset_task_cancel(tp); netif_tx_stop_all_queues(dev); @@ -15685,7 +15700,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) if (tp->fw) release_firmware(tp->fw); - cancel_work_sync(&tp->reset_task); + tg3_reset_task_cancel(tp); if (tg3_flag(tp, USE_PHYLIB)) { tg3_phy_fini(tp); @@ -15719,7 +15734,7 @@ static int tg3_suspend(struct device *device) if (!netif_running(dev)) return 0; - flush_work_sync(&tp->reset_task); + tg3_reset_task_cancel(tp); tg3_phy_stop(tp); tg3_netif_stop(tp); @@ -15835,7 +15850,7 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, tg3_flag_clear(tp, RESTART_TIMER); /* Want to make sure that the reset task doesn't run */ - cancel_work_sync(&tp->reset_task); + tg3_reset_task_cancel(tp); tg3_flag_clear(tp, TX_RECOVERY_PENDING); tg3_flag_clear(tp, RESTART_TIMER); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index acfa265733ad..610fd84cc60f 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -2922,6 +2922,7 @@ enum TG3_FLAGS { TG3_FLAG_APE_HAS_NCSI, TG3_FLAG_5717_PLUS, TG3_FLAG_4K_FIFO_LIMIT, + TG3_FLAG_RESET_TASK_PENDING, /* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */ TG3_FLAG_NUMBER_OF_FLAGS, /* Last entry in enum TG3_FLAGS */ From 5b1906241905d9bd1abe920854b3d43c2b9c85e1 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 4 Nov 2011 09:15:04 +0000 Subject: [PATCH 1454/1596] tg3: Eliminate timer race with reset_task During shutdown, it is impossible to reliably disable the timer and reset_task threads. Each thread can schedule the other, which leads to shutdown code that chases its tail. To fix the problem, this patch removes the ability of tg3_reset_task to schedule a new timer thread. To support this change, tg3_timer no longer terminates itself, but rather goes into a polling mode. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 14 ++------------ drivers/net/ethernet/broadcom/tg3.h | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index d4a85b795344..cc7349fd7fcd 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6352,7 +6352,6 @@ static void tg3_reset_task(struct work_struct *work) { struct tg3 *tp = container_of(work, struct tg3, reset_task); int err; - unsigned int restart_timer; tg3_full_lock(tp, 0); @@ -6370,9 +6369,6 @@ static void tg3_reset_task(struct work_struct *work) tg3_full_lock(tp, 1); - restart_timer = tg3_flag(tp, RESTART_TIMER); - tg3_flag_clear(tp, RESTART_TIMER); - if (tg3_flag(tp, TX_RECOVERY_PENDING)) { tp->write32_tx_mbox = tg3_write32_tx_mbox; tp->write32_rx_mbox = tg3_write_flush_reg32; @@ -6387,9 +6383,6 @@ static void tg3_reset_task(struct work_struct *work) tg3_netif_start(tp); - if (restart_timer) - mod_timer(&tp->timer, jiffies + 1); - out: tg3_full_unlock(tp); @@ -9218,7 +9211,7 @@ static void tg3_timer(unsigned long __opaque) { struct tg3 *tp = (struct tg3 *) __opaque; - if (tp->irq_sync) + if (tp->irq_sync || tg3_flag(tp, RESET_TASK_PENDING)) goto restart_timer; spin_lock(&tp->lock); @@ -9241,10 +9234,9 @@ static void tg3_timer(unsigned long __opaque) } if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tg3_flag_set(tp, RESTART_TIMER); spin_unlock(&tp->lock); tg3_reset_task_schedule(tp); - return; + goto restart_timer; } } @@ -15847,12 +15839,10 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, tg3_netif_stop(tp); del_timer_sync(&tp->timer); - tg3_flag_clear(tp, RESTART_TIMER); /* Want to make sure that the reset task doesn't run */ tg3_reset_task_cancel(tp); tg3_flag_clear(tp, TX_RECOVERY_PENDING); - tg3_flag_clear(tp, RESTART_TIMER); netif_device_detach(netdev); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 610fd84cc60f..94b4bd049a33 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -2879,7 +2879,6 @@ enum TG3_FLAGS { TG3_FLAG_JUMBO_CAPABLE, TG3_FLAG_CHIP_RESETTING, TG3_FLAG_INIT_COMPLETE, - TG3_FLAG_RESTART_TIMER, TG3_FLAG_TSO_BUG, TG3_FLAG_IS_5788, TG3_FLAG_MAX_RXPEND_64, From 5ae7fa06bb90421bc63f1f1e56ab241b49bc7b91 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 4 Nov 2011 09:15:05 +0000 Subject: [PATCH 1455/1596] tg3: Update version to 3.121 This patch updates the tg3 version to 3.121. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index cc7349fd7fcd..bf4074167d6a 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -89,10 +89,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 120 +#define TG3_MIN_NUM 121 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "August 18, 2011" +#define DRV_MODULE_RELDATE "November 2, 2011" #define RESET_KIND_SHUTDOWN 0 #define RESET_KIND_INIT 1 From 729e72a10930ef765c11a5a35031ba47f18221c4 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 2 Nov 2011 12:11:53 +0000 Subject: [PATCH 1456/1596] macvlan: receive multicast with local address When implementing VRRP v2 using macvlan several problems were discovered. VRRP is weird in that all routers participating in a redundant group use the same virtual MAC address. Macvlan is a natural driver to use for this but it doesn't work. The problem is that packets with a macvlan device's source address are not received. The problem is actually a regression that date back almost 2 years now. The original problems started with: commit 618e1b7482f7a8a4c6c6e8ccbe140e4c331df4e9 Author: Arnd Bergmann Date: Thu Nov 26 06:07:10 2009 +0000 macvlan: implement bridge, VEPA and private mode This patches restores the original 2.6.32 behavior. Allowing multicast packets received with the VRRP source address to be received. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index a3ce3d4561ed..74134970b709 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -192,6 +192,13 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) */ macvlan_broadcast(skb, port, src->dev, MACVLAN_MODE_VEPA); + else { + /* forward to original port. */ + vlan = src; + ret = macvlan_broadcast_one(skb, vlan, eth, 0); + goto out; + } + return RX_HANDLER_PASS; } From 433aee04a447fb2e769c4570f327d9c2a956117b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 2 Nov 2011 00:30:52 +0000 Subject: [PATCH 1457/1596] i825xx:xscale:8390:freescale: Fix Kconfig dependancies i825xx and xscale are "sub" Kconfigs to NET_VENDOR_INTEL, so NET_VENDOR_INTEL should contain ALL the dependencies of the "sub" Kconfigs. Same with 8390 is a "sub" Kconfig to NET_VENDOR_NATSEMI, so NET_VENDOR_NATSEMI needs to contains ALL the dependencies. Freescale Kconfig only had fs_enet as a sub Kconfig, and already contained the needed dependencies, just cleaned up the dependencies. Reported-by: Geert Uytterhoeven Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/Kconfig | 3 +-- drivers/net/ethernet/intel/Kconfig | 6 +++++- drivers/net/ethernet/natsemi/Kconfig | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 1cf671643d1f..c520cfd3b298 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -7,8 +7,7 @@ config NET_VENDOR_FREESCALE default y depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \ M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || ARCH_MXS || \ - (PPC_MPC52xx && PPC_BESTCOMM) + ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 61029dc7fa6f..76213162fbe3 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -5,7 +5,11 @@ config NET_VENDOR_INTEL bool "Intel devices" default y - depends on PCI || PCI_MSI + depends on PCI || PCI_MSI || ISA || ISA_DMA_API || ARM || \ + ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \ + GSC || BVME6000 || MVME16x || ARCH_ENP2611 || \ + (ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR) || \ + EXPERIMENTAL ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from diff --git a/drivers/net/ethernet/natsemi/Kconfig b/drivers/net/ethernet/natsemi/Kconfig index 4a6b9fd073b6..eb836f770f50 100644 --- a/drivers/net/ethernet/natsemi/Kconfig +++ b/drivers/net/ethernet/natsemi/Kconfig @@ -5,7 +5,10 @@ config NET_VENDOR_NATSEMI bool "National Semi-conductor devices" default y - depends on MCA || MAC || MACH_JAZZ || PCI || XTENSA_PLATFORM_XT2000 + depends on AMIGA_PCMCIA || ARM || EISA || EXPERIMENTAL || H8300 || \ + ISA || M32R || MAC || MACH_JAZZ || MACH_TX49XX || MCA || \ + MCA_LEGACY || MIPS || PCI || PCMCIA || SUPERH || \ + XTENSA_PLATFORM_XT2000 || ZORRO ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from From c30bc94758ae2a38a5eb31767c1985c0aae0950b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 Nov 2011 00:07:32 +0000 Subject: [PATCH 1458/1596] netlink: validate NLA_MSECS length L2TP for example uses NLA_MSECS like this: policy: [L2TP_ATTR_RECV_TIMEOUT] = { .type = NLA_MSECS, }, code: if (info->attrs[L2TP_ATTR_RECV_TIMEOUT]) cfg.reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]); As nla_get_msecs() is essentially nla_get_u64() plus the conversion to a HZ-based value, this will not properly reject attributes from userspace that aren't long enough and might overrun the message. Add NLA_MSECS to the attribute minlen array to check the size properly. Cc: Thomas Graf Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- lib/nlattr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nlattr.c b/lib/nlattr.c index ac09f2226dc7..a8408b6cacdf 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -20,6 +20,7 @@ static const u16 nla_attr_minlen[NLA_TYPE_MAX+1] = { [NLA_U16] = sizeof(u16), [NLA_U32] = sizeof(u32), [NLA_U64] = sizeof(u64), + [NLA_MSECS] = sizeof(u64), [NLA_NESTED] = NLA_HDRLEN, }; From 4b6cc7284ddc9a54910f111085ebf0143ef3f5bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 Nov 2011 00:10:05 +0000 Subject: [PATCH 1459/1596] netlink: clarify attribute length check documentation The documentation for how the length of attributes is checked is wrong ("Exact length" isn't true, the policy checks are for "minimum length") and a bit misleading. Make it more complete and explain what really happens. Cc: Thomas Graf Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/netlink.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 98c185441bee..cb1f3504687f 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -192,8 +192,15 @@ enum { * NLA_NUL_STRING Maximum length of string (excluding NUL) * NLA_FLAG Unused * NLA_BINARY Maximum length of attribute payload - * NLA_NESTED_COMPAT Exact length of structure payload - * All other Exact length of attribute payload + * NLA_NESTED Don't use `len' field -- length verification is + * done by checking len of nested header (or empty) + * NLA_NESTED_COMPAT Minimum length of structure payload + * NLA_U8, NLA_U16, + * NLA_U32, NLA_U64, + * NLA_MSECS Leaving the length field zero will verify the + * given type fits, using it verifies minimum length + * just like "All other" + * All other Minimum length of attribute payload * * Example: * static const struct nla_policy my_policy[ATTR_MAX+1] = { From 27d240fdae2808d727ad9ce48ec029731a457524 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Fri, 4 Nov 2011 12:17:17 +0000 Subject: [PATCH 1460/1596] sky2: fix regression on Yukon Optima Changes to support other Optima types, introduced an accidental regression that caused 88E8059 to come up in 10Mbit/sec. The Yukon Optima supports a reverse auto-negotiation feature that was incorrectly setup, and not needed. The feature could be used to allow wake-on-lan at higher speeds. But doing it correctly would require other changes to initialization. Reported-by: Pavel Mateja Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index cbd026f3bc57..fdc6c394c683 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -366,17 +366,6 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_FE_SPEC_2, spec); } } else { - if (hw->chip_id >= CHIP_ID_YUKON_OPT) { - u16 ctrl2 = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL_2); - - /* enable PHY Reverse Auto-Negotiation */ - ctrl2 |= 1u << 13; - - /* Write PHY changes (SW-reset must follow) */ - gm_phy_write(hw, port, PHY_MARV_EXT_CTRL_2, ctrl2); - } - - /* disable energy detect */ ctrl &= ~PHY_M_PC_EN_DET_MSK; From 589665f5a6008dbce1d0af2cb93e94a80bf78151 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Nov 2011 08:21:38 +0000 Subject: [PATCH 1461/1596] bonding: comparing a u8 with -1 is always false slave->duplex is a u8 type so the in bond_info_show_slave() when we check "if (slave->duplex == -1)", it's always false. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 4 ++-- drivers/net/bonding/bond_procfs.c | 4 ++-- include/linux/ethtool.h | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b2b9109b6712..b0c577256487 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -560,8 +560,8 @@ static int bond_update_speed_duplex(struct slave *slave) u32 slave_speed; int res; - slave->speed = -1; - slave->duplex = -1; + slave->speed = SPEED_UNKNOWN; + slave->duplex = DUPLEX_UNKNOWN; res = __ethtool_get_settings(slave_dev, &ecmd); if (res < 0) diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index d2ff52e63cbb..17206da2fab7 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -157,12 +157,12 @@ static void bond_info_show_slave(struct seq_file *seq, seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", (slave->link == BOND_LINK_UP) ? "up" : "down"); - if (slave->speed == -1) + if (slave->speed == SPEED_UNKNOWN) seq_printf(seq, "Speed: %s\n", "Unknown"); else seq_printf(seq, "Speed: %d Mbps\n", slave->speed); - if (slave->duplex == -1) + if (slave->duplex == DUPLEX_UNKNOWN) seq_printf(seq, "Duplex: %s\n", "Unknown"); else seq_printf(seq, "Duplex: %s\n", slave->duplex ? "full" : "half"); diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 45f00b61c096..de33de1e2052 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -1097,10 +1097,12 @@ struct ethtool_ops { #define SPEED_1000 1000 #define SPEED_2500 2500 #define SPEED_10000 10000 +#define SPEED_UNKNOWN -1 /* Duplex, half or full. */ #define DUPLEX_HALF 0x00 #define DUPLEX_FULL 0x01 +#define DUPLEX_UNKNOWN 0xff /* Which connector port. */ #define PORT_TP 0x00 From c4e2d2457afd6da3ddee18c2a1befca287e029c7 Mon Sep 17 00:00:00 2001 From: Sanjeev Premi Date: Thu, 13 Oct 2011 21:44:10 +0530 Subject: [PATCH 1462/1596] ARM: OMAP: Fix errors and warnings when building for one board When customizing omap2plus_defconfig to build for only one board (omap3evm), I came across these warnings and errors (filenames truncated): arch/arm/mach-omap2/board-generic.c:76:20: warning: 'omap4_init' defined but not used arch/arm/mach-omap2/built-in.o: In function `omap2420_init_early': arch/arm/mach-omap2/io.c:364: undefined reference to `omap2_set_globals_242x' arch/arm/mach-omap2/io.c:366: undefined reference to `omap2xxx_voltagedomains_init' arch/arm/mach-omap2/io.c:367: undefined reference to `omap242x_powerdomains_init' arch/arm/mach-omap2/io.c:368: undefined reference to `omap242x_clockdomains_init' arch/arm/mach-omap2/io.c:369: undefined reference to `omap2420_hwmod_init' arch/arm/mach-omap2/built-in.o: In function `omap2430_init_early': arch/arm/mach-omap2/io.c:376: undefined reference to `omap2_set_globals_243x' arch/arm/mach-omap2/io.c:378: undefined reference to `omap2xxx_voltagedomains_init' arch/arm/mach-omap2/io.c:379: undefined reference to `omap243x_powerdomains_init' arch/arm/mach-omap2/io.c:380: undefined reference to `omap243x_clockdomains_init' arch/arm/mach-omap2/io.c:381: undefined reference to `omap2430_hwmod_init' arch/arm/mach-omap2/built-in.o: In function `omap4430_init_early': arch/arm/mach-omap2/io.c:436: undefined reference to `omap2_set_globals_443x' arch/arm/mach-omap2/io.c:438: undefined reference to `omap44xx_voltagedomains_init' arch/arm/mach-omap2/io.c:439: undefined reference to `omap44xx_powerdomains_init' arch/arm/mach-omap2/io.c:440: undefined reference to `omap44xx_clockdomains_init' arch/arm/mach-omap2/io.c:441: undefined reference to `omap44xx_hwmod_init' This patch fixes them. Signed-off-by: Sanjeev Premi Acked-by: Thomas Weber [tony@atomide.com: updated to fix warnings for board-generic.c] Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-generic.c | 8 ++++++++ arch/arm/mach-omap2/io.c | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 0cc9094e5ee0..fb55fa3dad5a 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -28,6 +28,7 @@ * XXX: Still needed to boot until the i2c & twl driver is adapted to * device-tree */ +#ifdef CONFIG_ARCH_OMAP4 static struct twl4030_platform_data sdp4430_twldata = { .irq_base = TWL6030_IRQ_BASE, .irq_end = TWL6030_IRQ_END, @@ -37,7 +38,9 @@ static void __init omap4_i2c_init(void) { omap4_pmic_init("twl6030", &sdp4430_twldata); } +#endif +#ifdef CONFIG_ARCH_OMAP3 static struct twl4030_platform_data beagle_twldata = { .irq_base = TWL4030_IRQ_BASE, .irq_end = TWL4030_IRQ_END, @@ -47,6 +50,7 @@ static void __init omap3_i2c_init(void) { omap3_pmic_init("twl4030", &beagle_twldata); } +#endif static struct of_device_id omap_dt_match_table[] __initdata = { { .compatible = "simple-bus", }, @@ -72,17 +76,21 @@ static void __init omap_generic_init(void) of_platform_populate(NULL, omap_dt_match_table, NULL, NULL); } +#ifdef CONFIG_ARCH_OMAP4 static void __init omap4_init(void) { omap4_i2c_init(); omap_generic_init(); } +#endif +#ifdef CONFIG_ARCH_OMAP3 static void __init omap3_init(void) { omap3_i2c_init(); omap_generic_init(); } +#endif #if defined(CONFIG_SOC_OMAP2420) static const char *omap242x_boards_compat[] __initdata = { diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index a5d8dce2a70b..25d20ced03e1 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -359,6 +359,7 @@ static void __init omap_hwmod_init_postsetup(void) omap_pm_if_early_init(); } +#ifdef CONFIG_ARCH_OMAP2 void __init omap2420_init_early(void) { omap2_set_globals_242x(); @@ -382,11 +383,13 @@ void __init omap2430_init_early(void) omap_hwmod_init_postsetup(); omap2430_clk_init(); } +#endif /* * Currently only board-omap3beagle.c should call this because of the * same machine_id for 34xx and 36xx beagle.. Will get fixed with DT. */ +#ifdef CONFIG_ARCH_OMAP3 void __init omap3_init_early(void) { omap2_set_globals_3xxx(); @@ -430,7 +433,9 @@ void __init ti816x_init_early(void) omap_hwmod_init_postsetup(); omap3xxx_clk_init(); } +#endif +#ifdef CONFIG_ARCH_OMAP4 void __init omap4430_init_early(void) { omap2_set_globals_443x(); @@ -442,6 +447,7 @@ void __init omap4430_init_early(void) omap_hwmod_init_postsetup(); omap4xxx_clk_init(); } +#endif void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0, struct omap_sdrc_params *sdrc_cs1) From 927dbbb22c54347a0ba3a4eab2cbc46260afad32 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 3 Nov 2011 10:41:22 +0200 Subject: [PATCH 1463/1596] ARM: OMAP2+: devices: Fixes for McPDM Commit f718e2c034bf6ff872106344935006230764cb12 (ARM: OMAP2+: devices: Remove all omap_device_pm_latency structures) removed these structures. Commit 3528c58eb9e818b7821501afa2916eb12131994a (OMAP: omap_device: when building return platform_device instead of omap_device) now returns platform_device instead of omap_device. Fix up the omap-mcpdm init function since this part comes via sound tree, and there has been changes regarding to hwmod/omap_device_build. Signed-off-by: Peter Ujfalusi CC: Benoit Cousson CC: Kevin Hilman [tony@atomide.com: updated comments] Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/devices.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 68ec03152d5f..c15cfada5f13 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -318,18 +318,10 @@ static inline void omap_init_audio(void) {} #if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \ defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE) -static struct omap_device_pm_latency omap_mcpdm_latency[] = { - { - .deactivate_func = omap_device_idle_hwmods, - .activate_func = omap_device_enable_hwmods, - .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, - }, -}; - static void omap_init_mcpdm(void) { struct omap_hwmod *oh; - struct omap_device *od; + struct platform_device *pdev; oh = omap_hwmod_lookup("mcpdm"); if (!oh) { @@ -337,11 +329,8 @@ static void omap_init_mcpdm(void) return; } - od = omap_device_build("omap-mcpdm", -1, oh, NULL, 0, - omap_mcpdm_latency, - ARRAY_SIZE(omap_mcpdm_latency), 0); - if (IS_ERR(od)) - printk(KERN_ERR "Could not build omap_device for omap-mcpdm-dai\n"); + pdev = omap_device_build("omap-mcpdm", -1, oh, NULL, 0, NULL, 0, 0); + WARN(IS_ERR(pdev), "Can't build omap_device for omap-mcpdm.\n"); } #else static inline void omap_init_mcpdm(void) {} From d4fc7eb5c597c65739faa776783b2e28bf0d7296 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 2 Nov 2011 09:40:11 +0800 Subject: [PATCH 1464/1596] ARM: OMAP2+: l3-noc: Include linux/module.h Include linux/module.h to fix below build error: CC arch/arm/mach-omap2/omap_l3_noc.o arch/arm/mach-omap2/omap_l3_noc.c:240: error: expected ',' or ';' before 'MODULE_DEVICE_TABLE' arch/arm/mach-omap2/omap_l3_noc.c:250: error: 'THIS_MODULE' undeclared here (not in a function) make[1]: *** [arch/arm/mach-omap2/omap_l3_noc.o] Error 1 make: *** [arch/arm/mach-omap2] Error 2 Signed-off-by: Axel Lin Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_l3_noc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-omap2/omap_l3_noc.c b/arch/arm/mach-omap2/omap_l3_noc.c index c8b1bef92e5a..6a66aa5e2a5b 100644 --- a/arch/arm/mach-omap2/omap_l3_noc.c +++ b/arch/arm/mach-omap2/omap_l3_noc.c @@ -20,6 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ +#include #include #include #include From 869dec1582af755a84ba993580f6588559e197b4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 2 Nov 2011 09:49:46 +0800 Subject: [PATCH 1465/1596] ARM: OMAP: dmtimer: Include linux/module.h Include linux/module.h to fix below build error: CC arch/arm/plat-omap/dmtimer.o arch/arm/plat-omap/dmtimer.c:184: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:184: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:184: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:215: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:215: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:215: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:228: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:228: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:228: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:234: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:234: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:234: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:240: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:240: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:240: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:248: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:248: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:248: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:294: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:294: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:294: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:302: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:302: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:302: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:316: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:316: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:316: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:344: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:344: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:344: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:361: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:361: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:361: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:380: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:380: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:380: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:406: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:406: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:406: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:443: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:443: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:443: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:468: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:468: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:468: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:494: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:494: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:494: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:517: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:517: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:517: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:534: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:534: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:534: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:549: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:549: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:549: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:561: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:561: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:561: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:572: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:572: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:572: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:587: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:587: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:587: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:604: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:604: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' arch/arm/plat-omap/dmtimer.c:604: warning: parameter names (without types) in function declaration arch/arm/plat-omap/dmtimer.c:746: error: expected declaration specifiers or '...' before string constant arch/arm/plat-omap/dmtimer.c:746: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:746: warning: type defaults to 'int' in declaration of 'MODULE_DESCRIPTION' arch/arm/plat-omap/dmtimer.c:746: warning: function declaration isn't a prototype arch/arm/plat-omap/dmtimer.c:747: error: expected declaration specifiers or '...' before string constant arch/arm/plat-omap/dmtimer.c:747: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:747: warning: type defaults to 'int' in declaration of 'MODULE_LICENSE' arch/arm/plat-omap/dmtimer.c:747: warning: function declaration isn't a prototype arch/arm/plat-omap/dmtimer.c:748: error: expected declaration specifiers or '...' before string constant arch/arm/plat-omap/dmtimer.c:748: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:748: warning: type defaults to 'int' in declaration of 'MODULE_ALIAS' arch/arm/plat-omap/dmtimer.c:748: warning: function declaration isn't a prototype arch/arm/plat-omap/dmtimer.c:749: error: expected declaration specifiers or '...' before string constant arch/arm/plat-omap/dmtimer.c:749: warning: data definition has no type or storage class arch/arm/plat-omap/dmtimer.c:749: warning: type defaults to 'int' in declaration of 'MODULE_AUTHOR' arch/arm/plat-omap/dmtimer.c:749: warning: function declaration isn't a prototype make[1]: *** [arch/arm/plat-omap/dmtimer.o] Error 1 make: *** [arch/arm/plat-omap] Error 2 Signed-off-by: Axel Lin Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dmtimer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 2def4e1990ed..af3b92be8459 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -35,6 +35,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include From af504e5d39de35dc3de5f42c357fe1b519fea33f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 2 Nov 2011 12:54:03 +0100 Subject: [PATCH 1466/1596] ARM: OMAP: I2C: Fix omap_register_i2c_bus() return value on success Commit 4d17aeb1c5b2375769446d13012a98e6d265ec13 ("OMAP: I2C: split device registration and convert OMAP2+ to omap_device") makes omap2_i2c_add_bus() return a pointer to an omap_device instead on success instead of 0. This breaks the omap_register_i2c_bus() ABI and results in the igep0020 board code detecting an I2C bus registration error when there is none. Fix the problem by using PTR_RET() instead of PTR_ERR() in omap2_i2c_add_bus(). Reported-by: Alexander Kinzer Signed-off-by: Laurent Pinchart [tony@atomide.com: updated to return pdev instead of od] Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index 679cbd49c019..db071bc71c4d 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -184,7 +184,7 @@ static inline int omap2_i2c_add_bus(int bus_id) NULL, 0, 0); WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", name); - return PTR_ERR(pdev); + return PTR_RET(pdev); } #else static inline int omap2_i2c_add_bus(int bus_id) From ace9021698ef7d298e6d184ae2880b1cb3ebc4c7 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 6 Oct 2011 14:39:28 -0600 Subject: [PATCH 1467/1596] ARM: OMAP3: hwmod: fix variant registration and remove SmartReflex from common list Commit d6504acd2125984c61dce24727dd3842d0144015 ("OMAP2+: hwmod: remove OMAP_CHIP*") tests the inverse condition of what it should be testing for the return value from omap_hwmod_register(). This causes several IP blocks to not be registered on several OMAP3 family devices. Fixing that bug also unmasked another bug, originally reported by Chase Maupin and then subsequently by Abhilash K V , which caused SmartReflex IP blocks to be registered on SoCs that don't support them. Thanks to Russell King - ARM Linux for comments on a previous version of the patch. Signed-off-by: Paul Walmsley Cc: Chase Maupin Cc: Abhilash K V Cc: Russell King - ARM Linux Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 87a3b01d254c..bc9035ec87fc 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -3270,7 +3270,7 @@ int __init omap3xxx_hwmod_init(void) /* Register hwmods common to all OMAP3 */ r = omap_hwmod_register(omap3xxx_hwmods); - if (!r) + if (r < 0) return r; rev = omap_rev(); @@ -3295,7 +3295,7 @@ int __init omap3xxx_hwmod_init(void) }; r = omap_hwmod_register(h); - if (!r) + if (r < 0) return r; /* From ff2beb1d9f2fecc3f5c1d67bfec1183a5a476586 Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Mon, 3 Oct 2011 17:52:50 +0530 Subject: [PATCH 1468/1596] ARM: OMAP4: hsmmc: Fix Pbias configuration on regulator OFF MMC1 data line IO's are powered down in before set regulator function. IO's should not be powered ON when regulator is OFF. Keep the IO's in power pown mode after regulator OFF otherwise VMODE_ERROR interrupt is generated due to mismatch in input (regulator) voltage and MMC IO drive voltage. Delete incorrect comments which are not applicable for OMAP4. Signed-off-by: Balaji T K Signed-off-by: Kishore Kadiyala Reported-by: Viswanath Puttagunta Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/hsmmc.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 77085847e4e7..d663649f6923 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -129,15 +129,11 @@ static void omap4_hsmmc1_before_set_reg(struct device *dev, int slot, * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the * card with Vcc regulator (from twl4030 or whatever). OMAP has both * 1.8V and 3.0V modes, controlled by the PBIAS register. - * - * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which - * is most naturally TWL VSIM; those pins also use PBIAS. - * - * FIXME handle VMMC1A as needed ... */ reg = omap4_ctrl_pad_readl(control_pbias_offset); reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK | - OMAP4_MMC1_PWRDNZ_MASK); + OMAP4_MMC1_PWRDNZ_MASK | + OMAP4_MMC1_PBIASLITE_VMODE_MASK); omap4_ctrl_pad_writel(reg, control_pbias_offset); } @@ -172,12 +168,6 @@ static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot, reg &= ~(OMAP4_MMC1_PWRDNZ_MASK); omap4_ctrl_pad_writel(reg, control_pbias_offset); } - } else { - reg = omap4_ctrl_pad_readl(control_pbias_offset); - reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK | - OMAP4_MMC1_PWRDNZ_MASK | - OMAP4_MMC1_PBIASLITE_VMODE_MASK); - omap4_ctrl_pad_writel(reg, control_pbias_offset); } } From c862dd706759c48a8a45af140330544724f170f9 Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Mon, 3 Oct 2011 17:52:51 +0530 Subject: [PATCH 1469/1596] ARM: OMAP4: hsmmc: configure SDMMC1_DR0 properly Fix the typo, instead it should be SDMMC1 USBC1 is not related to MMC1 I/Os Signed-off-by: Balaji T K Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/hsmmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index d663649f6923..f4a1020559a7 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -479,7 +479,7 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK); reg &= ~(OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK | OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK); - reg |= (OMAP4_USBC1_DR0_SPEEDCTRL_MASK| + reg |= (OMAP4_SDMMC1_DR0_SPEEDCTRL_MASK | OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK | OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK); omap4_ctrl_pad_writel(reg, control_mmc1); From fc01387302c01899e3cc67d3c81fd4287db9bab9 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Jun 2011 16:56:23 +0300 Subject: [PATCH 1470/1596] ARM: OMAP: change get_context_loss_count ret value to int get_context_loss_count functions return context loss count as u32, and zero means an error. However, zero is also returned when context has never been lost and could also be returned when the context loss count has wrapped and goes to zero. Change the functions to return an int, with negative value meaning an error. OMAP HSMMC code uses omap_pm_get_dev_context_loss_count(), but as the hsmmc code handles the returned value as an int, with negative value meaning an error, this patch actually fixes hsmmc code also. Signed-off-by: Tomi Valkeinen Acked-by: Kevin Hilman Acked-by: Paul Walmsley [tony@atomide.com: updated to fix a warning with recent dmtimer changes] Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 2 +- arch/arm/mach-omap2/powerdomain.c | 14 +++++++---- arch/arm/mach-omap2/powerdomain.h | 2 +- arch/arm/plat-omap/include/plat/dmtimer.h | 4 ++-- arch/arm/plat-omap/include/plat/omap-pm.h | 4 ++-- arch/arm/plat-omap/include/plat/omap_device.h | 2 +- arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 +- arch/arm/plat-omap/omap-pm-noop.c | 24 +++++++++++++------ arch/arm/plat-omap/omap_device.c | 2 +- 9 files changed, 36 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index d71380705080..6b3088db83b7 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2625,7 +2625,7 @@ int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) * Returns the context loss count of the powerdomain assocated with @oh * upon success, or zero if no powerdomain exists for @oh. */ -u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) +int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) { struct powerdomain *pwrdm; int ret = 0; diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 5164d587ef52..8a18d1bd61c8 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1002,16 +1002,16 @@ int pwrdm_post_transition(void) * @pwrdm: struct powerdomain * to wait for * * Context loss count is the sum of powerdomain off-mode counter, the - * logic off counter and the per-bank memory off counter. Returns 0 + * logic off counter and the per-bank memory off counter. Returns negative * (and WARNs) upon error, otherwise, returns the context loss count. */ -u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm) +int pwrdm_get_context_loss_count(struct powerdomain *pwrdm) { int i, count; if (!pwrdm) { WARN(1, "powerdomain: %s: pwrdm is null\n", __func__); - return 0; + return -ENODEV; } count = pwrdm->state_counter[PWRDM_POWER_OFF]; @@ -1020,7 +1020,13 @@ u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm) for (i = 0; i < pwrdm->banks; i++) count += pwrdm->ret_mem_off_counter[i]; - pr_debug("powerdomain: %s: context loss count = %u\n", + /* + * Context loss count has to be a non-negative value. Clear the sign + * bit to get a value range from 0 to INT_MAX. + */ + count &= INT_MAX; + + pr_debug("powerdomain: %s: context loss count = %d\n", pwrdm->name, count); return count; diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 42e6dd8f2a78..0d72a8a8ce4d 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -217,7 +217,7 @@ int pwrdm_clkdm_state_switch(struct clockdomain *clkdm); int pwrdm_pre_transition(void); int pwrdm_post_transition(void); int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); -u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm); +int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); extern void omap242x_powerdomains_init(void); diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index d11025e6e7a4..9418f00b6c38 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -104,7 +104,7 @@ struct dmtimer_platform_data { bool loses_context; - u32 (*get_context_loss_count)(struct device *dev); + int (*get_context_loss_count)(struct device *dev); }; struct omap_dm_timer *omap_dm_timer_request(void); @@ -279,7 +279,7 @@ struct omap_dm_timer { struct platform_device *pdev; struct list_head node; - u32 (*get_context_loss_count)(struct device *dev); + int (*get_context_loss_count)(struct device *dev); }; int omap_dm_timer_prepare(struct omap_dm_timer *timer); diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h index 0840df813f4f..67faa7b8fe92 100644 --- a/arch/arm/plat-omap/include/plat/omap-pm.h +++ b/arch/arm/plat-omap/include/plat/omap-pm.h @@ -342,9 +342,9 @@ unsigned long omap_pm_cpu_get_freq(void); * driver must restore device context. If the number of context losses * exceeds the maximum positive integer, the function will wrap to 0 and * continue counting. Returns the number of context losses for this device, - * or zero upon error. + * or negative value upon error. */ -u32 omap_pm_get_dev_context_loss_count(struct device *dev); +int omap_pm_get_dev_context_loss_count(struct device *dev); void omap_pm_enable_off_mode(void); void omap_pm_disable_off_mode(void); diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h index 12c5b0c345bf..51423d2727a5 100644 --- a/arch/arm/plat-omap/include/plat/omap_device.h +++ b/arch/arm/plat-omap/include/plat/omap_device.h @@ -107,7 +107,7 @@ struct device *omap_device_get_by_hwmod_name(const char *oh_name); int omap_device_align_pm_lat(struct platform_device *pdev, u32 new_wakeup_lat_limit); struct powerdomain *omap_device_get_pwrdm(struct omap_device *od); -u32 omap_device_get_context_loss_count(struct platform_device *pdev); +int omap_device_get_context_loss_count(struct platform_device *pdev); /* Other */ diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 5419f1a2aaa4..8b372ede17c1 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -600,7 +600,7 @@ int omap_hwmod_for_each_by_class(const char *classname, void *user); int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state); -u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh); +int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh); int omap_hwmod_no_setup_reset(struct omap_hwmod *oh); diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c index b0471bb2d47d..3dc3801aace4 100644 --- a/arch/arm/plat-omap/omap-pm-noop.c +++ b/arch/arm/plat-omap/omap-pm-noop.c @@ -27,7 +27,7 @@ #include static bool off_mode_enabled; -static u32 dummy_context_loss_counter; +static int dummy_context_loss_counter; /* * Device-driver-originated constraints (via board-*.c files) @@ -311,22 +311,32 @@ void omap_pm_disable_off_mode(void) #ifdef CONFIG_ARCH_OMAP2PLUS -u32 omap_pm_get_dev_context_loss_count(struct device *dev) +int omap_pm_get_dev_context_loss_count(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - u32 count; + int count; if (WARN_ON(!dev)) - return 0; + return -ENODEV; if (dev->parent == &omap_device_parent) { count = omap_device_get_context_loss_count(pdev); } else { WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context loss counter; device %s should be converted to omap_device", dev_name(dev)); - if (off_mode_enabled) - dummy_context_loss_counter++; + count = dummy_context_loss_counter; + + if (off_mode_enabled) { + count++; + /* + * Context loss count has to be a non-negative value. + * Clear the sign bit to get a value range from 0 to + * INT_MAX. + */ + count &= INT_MAX; + dummy_context_loss_counter = count; + } } pr_debug("OMAP PM: context loss count for dev %s = %d\n", @@ -337,7 +347,7 @@ u32 omap_pm_get_dev_context_loss_count(struct device *dev) #else -u32 omap_pm_get_dev_context_loss_count(struct device *dev) +int omap_pm_get_dev_context_loss_count(struct device *dev) { return dummy_context_loss_counter; } diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index cd90bedd9306..ef4ffc21bbae 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -426,7 +426,7 @@ static int _omap_device_notifier_call(struct notifier_block *nb, * return the context loss counter for that hwmod, otherwise return * zero. */ -u32 omap_device_get_context_loss_count(struct platform_device *pdev) +int omap_device_get_context_loss_count(struct platform_device *pdev) { struct omap_device *od; u32 ret = 0; From 30bd0129ce3f111bb5f96feafd9c64ba074e9b30 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 4 Nov 2011 13:18:02 +0200 Subject: [PATCH 1471/1596] MAINTAINERS: Update linux-omap git repository linux-omap is back at git.kernel.org. Path is the same than before except -2.6 appendix. Signed-off-by: Jarkko Nikula Signed-off-by: Tony Lindgren --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index c406f9ba1923..03067f549b84 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4662,7 +4662,7 @@ L: linux-omap@vger.kernel.org W: http://www.muru.com/linux/omap/ W: http://linux.omap.com/ Q: http://patchwork.kernel.org/project/linux-omap/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git S: Maintained F: arch/arm/*omap*/ From 0eb3c0f5a43f7dd90c4109927752659f147237b7 Mon Sep 17 00:00:00 2001 From: Bjarne Steinsbo Date: Thu, 6 Oct 2011 13:03:46 -0700 Subject: [PATCH 1472/1596] ARM: OMAP: usb: musb: OMAP: Delete unused function Not in use anymore. Signed-off-by: Bjarne Steinsbo Acked-by: Felipe Balbi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/usb-musb.c | 38 ---------------------------------- 1 file changed, 38 deletions(-) diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index 47fb5d607630..267975086a7b 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -60,44 +60,6 @@ static struct musb_hdrc_platform_data musb_plat = { static u64 musb_dmamask = DMA_BIT_MASK(32); -static void usb_musb_mux_init(struct omap_musb_board_data *board_data) -{ - switch (board_data->interface_type) { - case MUSB_INTERFACE_UTMI: - omap_mux_init_signal("usba0_otg_dp", OMAP_PIN_INPUT); - omap_mux_init_signal("usba0_otg_dm", OMAP_PIN_INPUT); - break; - case MUSB_INTERFACE_ULPI: - omap_mux_init_signal("usba0_ulpiphy_clk", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_stp", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dir", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_nxt", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dat0", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dat1", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dat2", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dat3", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dat4", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dat5", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dat6", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usba0_ulpiphy_dat7", - OMAP_PIN_INPUT_PULLDOWN); - break; - default: - break; - } -} - static struct omap_musb_board_data musb_default_board_data = { .interface_type = MUSB_INTERFACE_ULPI, .mode = MUSB_OTG, From e9614f35ba0f50d985fc27cbbafcb0346e1d4daa Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Tue, 6 Sep 2011 17:11:49 +0200 Subject: [PATCH 1473/1596] ARM: OMAP: Devkit8000: Remove double omap_mux_init_gpio Remove the init of card detect pin because omap_mux_init_gpio() is called during hsmmc initialization for the write protect and card detect pin. Signed-off-by: Thomas Weber Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-devkit8000.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c index 42918940c530..90154e411da0 100644 --- a/arch/arm/mach-omap2/board-devkit8000.c +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -226,7 +226,6 @@ static int devkit8000_twl_gpio_setup(struct device *dev, { int ret; - omap_mux_init_gpio(29, OMAP_PIN_INPUT); /* gpio + 0 is "mmc0_cd" (input/IRQ) */ mmc[0].gpio_cd = gpio + 0; omap2_hsmmc_init(mmc); From 2847111cb1ea1a6e2b25e6a26cc76f88575bc0bd Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 4 Oct 2011 23:20:40 +0200 Subject: [PATCH 1474/1596] ARM: OMAP2+: clock data: Remove redundant timer clkdev The commit 318c3e15cd55c73a26ae22a65a8183655b3003f9 added some "fck" clock alias to timer devices that are not needed anymore since hwmod framework will create them automatically. A warning was added to highlight and thus fix the redundancy. [ 0.616424] omap_timer.1: alias fck already exists [ 0.621948] omap_timer.2: alias fck already exists [ 0.627380] omap_timer.3: alias fck already exists [ 0.632781] omap_timer.4: alias fck already exists [ 0.638214] omap_timer.5: alias fck already exists [ 0.643615] omap_timer.6: alias fck already exists [ 0.649078] omap_timer.7: alias fck already exists [ 0.654479] omap_timer.8: alias fck already exists [ 0.659881] omap_timer.9: alias fck already exists [ 0.665283] omap_timer.10: alias fck already exists [ 0.670776] omap_timer.11: alias fck already exists Remove all the clkdev entries for timer fck alias. Signed-off-by: Benoit Cousson Cc: Tarun Kanti DebBarma Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock2420_data.c | 12 ------------ arch/arm/mach-omap2/clock2430_data.c | 12 ------------ arch/arm/mach-omap2/clock3xxx_data.c | 12 ------------ arch/arm/mach-omap2/clock44xx_data.c | 11 ----------- 4 files changed, 47 deletions(-) diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c index 14a6277dd184..61ad3855f10a 100644 --- a/arch/arm/mach-omap2/clock2420_data.c +++ b/arch/arm/mach-omap2/clock2420_data.c @@ -1898,18 +1898,6 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "pka_ick", &pka_ick, CK_242X), CLK(NULL, "usb_fck", &usb_fck, CK_242X), CLK("musb-hdrc", "fck", &osc_ck, CK_242X), - CLK("omap_timer.1", "fck", &gpt1_fck, CK_242X), - CLK("omap_timer.2", "fck", &gpt2_fck, CK_242X), - CLK("omap_timer.3", "fck", &gpt3_fck, CK_242X), - CLK("omap_timer.4", "fck", &gpt4_fck, CK_242X), - CLK("omap_timer.5", "fck", &gpt5_fck, CK_242X), - CLK("omap_timer.6", "fck", &gpt6_fck, CK_242X), - CLK("omap_timer.7", "fck", &gpt7_fck, CK_242X), - CLK("omap_timer.8", "fck", &gpt8_fck, CK_242X), - CLK("omap_timer.9", "fck", &gpt9_fck, CK_242X), - CLK("omap_timer.10", "fck", &gpt10_fck, CK_242X), - CLK("omap_timer.11", "fck", &gpt11_fck, CK_242X), - CLK("omap_timer.12", "fck", &gpt12_fck, CK_242X), CLK("omap_timer.1", "32k_ck", &func_32k_ck, CK_243X), CLK("omap_timer.2", "32k_ck", &func_32k_ck, CK_243X), CLK("omap_timer.3", "32k_ck", &func_32k_ck, CK_243X), diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c index ea6717cfa3c8..0cc12879e7b9 100644 --- a/arch/arm/mach-omap2/clock2430_data.c +++ b/arch/arm/mach-omap2/clock2430_data.c @@ -1998,18 +1998,6 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "mdm_intc_ick", &mdm_intc_ick, CK_243X), CLK("omap_hsmmc.0", "mmchsdb_fck", &mmchsdb1_fck, CK_243X), CLK("omap_hsmmc.1", "mmchsdb_fck", &mmchsdb2_fck, CK_243X), - CLK("omap_timer.1", "fck", &gpt1_fck, CK_243X), - CLK("omap_timer.2", "fck", &gpt2_fck, CK_243X), - CLK("omap_timer.3", "fck", &gpt3_fck, CK_243X), - CLK("omap_timer.4", "fck", &gpt4_fck, CK_243X), - CLK("omap_timer.5", "fck", &gpt5_fck, CK_243X), - CLK("omap_timer.6", "fck", &gpt6_fck, CK_243X), - CLK("omap_timer.7", "fck", &gpt7_fck, CK_243X), - CLK("omap_timer.8", "fck", &gpt8_fck, CK_243X), - CLK("omap_timer.9", "fck", &gpt9_fck, CK_243X), - CLK("omap_timer.10", "fck", &gpt10_fck, CK_243X), - CLK("omap_timer.11", "fck", &gpt11_fck, CK_243X), - CLK("omap_timer.12", "fck", &gpt12_fck, CK_243X), CLK("omap_timer.1", "32k_ck", &func_32k_ck, CK_243X), CLK("omap_timer.2", "32k_ck", &func_32k_ck, CK_243X), CLK("omap_timer.3", "32k_ck", &func_32k_ck, CK_243X), diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c index 65dd363163bc..5d0064a4fb5a 100644 --- a/arch/arm/mach-omap2/clock3xxx_data.c +++ b/arch/arm/mach-omap2/clock3xxx_data.c @@ -3464,18 +3464,6 @@ static struct omap_clk omap3xxx_clks[] = { CLK("musb-am35x", "fck", &hsotgusb_fck_am35xx, CK_AM35XX), CLK(NULL, "hecc_ck", &hecc_ck, CK_AM35XX), CLK(NULL, "uart4_ick", &uart4_ick_am35xx, CK_AM35XX), - CLK("omap_timer.1", "fck", &gpt1_fck, CK_3XXX), - CLK("omap_timer.2", "fck", &gpt2_fck, CK_3XXX), - CLK("omap_timer.3", "fck", &gpt3_fck, CK_3XXX), - CLK("omap_timer.4", "fck", &gpt4_fck, CK_3XXX), - CLK("omap_timer.5", "fck", &gpt5_fck, CK_3XXX), - CLK("omap_timer.6", "fck", &gpt6_fck, CK_3XXX), - CLK("omap_timer.7", "fck", &gpt7_fck, CK_3XXX), - CLK("omap_timer.8", "fck", &gpt8_fck, CK_3XXX), - CLK("omap_timer.9", "fck", &gpt9_fck, CK_3XXX), - CLK("omap_timer.10", "fck", &gpt10_fck, CK_3XXX), - CLK("omap_timer.11", "fck", &gpt11_fck, CK_3XXX), - CLK("omap_timer.12", "fck", &gpt12_fck, CK_3XXX), CLK("omap_timer.1", "32k_ck", &omap_32k_fck, CK_3XXX), CLK("omap_timer.2", "32k_ck", &omap_32k_fck, CK_3XXX), CLK("omap_timer.3", "32k_ck", &omap_32k_fck, CK_3XXX), diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index cbf9b68d4b94..0798a802497a 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -3377,17 +3377,6 @@ static struct omap_clk omap44xx_clks[] = { CLK("usbhs-omap.0", "usbhost_ick", &dummy_ck, CK_443X), CLK("usbhs-omap.0", "usbtll_fck", &dummy_ck, CK_443X), CLK("omap_wdt", "ick", &dummy_ck, CK_443X), - CLK("omap_timer.1", "fck", &timer1_fck, CK_443X), - CLK("omap_timer.2", "fck", &timer2_fck, CK_443X), - CLK("omap_timer.3", "fck", &timer3_fck, CK_443X), - CLK("omap_timer.4", "fck", &timer4_fck, CK_443X), - CLK("omap_timer.5", "fck", &timer5_fck, CK_443X), - CLK("omap_timer.6", "fck", &timer6_fck, CK_443X), - CLK("omap_timer.7", "fck", &timer7_fck, CK_443X), - CLK("omap_timer.8", "fck", &timer8_fck, CK_443X), - CLK("omap_timer.9", "fck", &timer9_fck, CK_443X), - CLK("omap_timer.10", "fck", &timer10_fck, CK_443X), - CLK("omap_timer.11", "fck", &timer11_fck, CK_443X), CLK("omap_timer.1", "32k_ck", &sys_32k_ck, CK_443X), CLK("omap_timer.2", "32k_ck", &sys_32k_ck, CK_443X), CLK("omap_timer.3", "32k_ck", &sys_32k_ck, CK_443X), From c16ae1e64e292054bc4c5a20724b40217bdc43dd Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 4 Oct 2011 23:20:41 +0200 Subject: [PATCH 1475/1596] ARM: OMAP2+: timer: Remove omap_device_pm_latency Remove the structure since a default one is now available. Signed-off-by: Benoit Cousson Cc: Kevin Hilman Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/timer.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index e49fc7be2229..037b0d7d4e05 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -408,14 +408,6 @@ static int omap2_dm_timer_set_src(struct platform_device *pdev, int source) return ret; } -struct omap_device_pm_latency omap2_dmtimer_latency[] = { - { - .deactivate_func = omap_device_idle_hwmods, - .activate_func = omap_device_enable_hwmods, - .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, - }, -}; - /** * omap_timer_init - build and register timer device with an * associated timer hwmod @@ -477,9 +469,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; #endif pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), - omap2_dmtimer_latency, - ARRAY_SIZE(omap2_dmtimer_latency), - 0); + NULL, 0, 0); if (IS_ERR(pdev)) { pr_err("%s: Can't build omap_device for %s: %s.\n", From be26a008414414c69a4ae9fe9877401c3ba62c5a Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 6 Oct 2011 17:05:51 -0700 Subject: [PATCH 1476/1596] ARM: OMAP1: Fix warnings about enabling 32 KiHz timer Fix "Enable 32kHz OS timer in order to allow sleep states in idle" warning. We are now compiling in bothe MPU timer and 32 KiHz timer, so this warning is only valid when MPU_TIMER is set and OMAP_DM_TIMER is not set. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index 495b3987d461..89ea20ca0ccc 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -116,7 +116,7 @@ void omap1_pm_idle(void) return; } -#ifdef CONFIG_OMAP_MPU_TIMER +#if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER) #warning Enable 32kHz OS timer in order to allow sleep states in idle use_idlect1 = use_idlect1 & ~(1 << 9); #else From 98e541ffaadf01fc4d202ad2bd187a14b671f1a4 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 4 Nov 2011 13:28:04 +0200 Subject: [PATCH 1477/1596] ARM: OMAP1: Remove unused omap-alsa.h There is no use for omap-alsa.h and board-palmz71.c doesn't need it either. Signed-off-by: Jarkko Nikula Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-palmz71.c | 1 - arch/arm/plat-omap/include/plat/omap-alsa.h | 123 -------------------- 2 files changed, 124 deletions(-) delete mode 100644 arch/arm/plat-omap/include/plat/omap-alsa.h diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c index c6fe61dfe856..42061573e380 100644 --- a/arch/arm/mach-omap1/board-palmz71.c +++ b/arch/arm/mach-omap1/board-palmz71.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/plat-omap/include/plat/omap-alsa.h b/arch/arm/plat-omap/include/plat/omap-alsa.h deleted file mode 100644 index b53055b390d0..000000000000 --- a/arch/arm/plat-omap/include/plat/omap-alsa.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * arch/arm/plat-omap/include/mach/omap-alsa.h - * - * Alsa Driver for AIC23 and TSC2101 codecs on OMAP platform boards. - * - * Copyright (C) 2006 Mika Laitio - * - * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil - * Written by Daniel Petrini, David Cohen, Anderson Briglia - * {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History - * ------- - * - * 2005/07/25 INdT-10LE Kernel Team - Alsa driver for omap osk, - * original version based in sa1100 driver - * and omap oss driver. - */ - -#ifndef __OMAP_ALSA_H -#define __OMAP_ALSA_H - -#include -#include -#include -#include -#include - -#define DMA_BUF_SIZE (1024 * 8) - -/* - * Buffer management for alsa and dma - */ -struct audio_stream { - char *id; /* identification string */ - int stream_id; /* numeric identification */ - int dma_dev; /* dma number of that device */ - int *lch; /* Chain of channels this stream is linked to */ - char started; /* to store if the chain was started or not */ - int dma_q_head; /* DMA Channel Q Head */ - int dma_q_tail; /* DMA Channel Q Tail */ - char dma_q_count; /* DMA Channel Q Count */ - int active:1; /* we are using this stream for transfer now */ - int period; /* current transfer period */ - int periods; /* current count of periods registerd in the DMA engine */ - spinlock_t dma_lock; /* for locking in DMA operations */ - struct snd_pcm_substream *stream; /* the pcm stream */ - unsigned linked:1; /* dma channels linked */ - int offset; /* store start position of the last period in the alsa buffer */ - int (*hw_start)(void); /* interface to start HW interface, e.g. McBSP */ - int (*hw_stop)(void); /* interface to stop HW interface, e.g. McBSP */ -}; - -/* - * Alsa card structure for aic23 - */ -struct snd_card_omap_codec { - struct snd_card *card; - struct snd_pcm *pcm; - long samplerate; - struct audio_stream s[2]; /* playback & capture */ -}; - -/* Codec specific information and function pointers. - * Codec (omap-alsa-aic23.c and omap-alsa-tsc2101.c) - * are responsible for defining the function pointers. - */ -struct omap_alsa_codec_config { - char *name; - struct omap_mcbsp_reg_cfg *mcbsp_regs_alsa; - struct snd_pcm_hw_constraint_list *hw_constraints_rates; - struct snd_pcm_hardware *snd_omap_alsa_playback; - struct snd_pcm_hardware *snd_omap_alsa_capture; - void (*codec_configure_dev)(void); - void (*codec_set_samplerate)(long); - void (*codec_clock_setup)(void); - int (*codec_clock_on)(void); - int (*codec_clock_off)(void); - int (*get_default_samplerate)(void); -}; - -/*********** Mixer function prototypes *************************/ -int snd_omap_mixer(struct snd_card_omap_codec *); -void snd_omap_init_mixer(void); - -#ifdef CONFIG_PM -void snd_omap_suspend_mixer(void); -void snd_omap_resume_mixer(void); -#endif - -int snd_omap_alsa_post_probe(struct platform_device *pdev, struct omap_alsa_codec_config *config); -int snd_omap_alsa_remove(struct platform_device *pdev); -#ifdef CONFIG_PM -int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state); -int snd_omap_alsa_resume(struct platform_device *pdev); -#else -#define snd_omap_alsa_suspend NULL -#define snd_omap_alsa_resume NULL -#endif - -void callback_omap_alsa_sound_dma(void *); - -#endif From 41eb2d813f558900884e240c2f723e36c7bd151f Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 6 Oct 2011 15:43:00 -0700 Subject: [PATCH 1478/1596] ARM: OMAP2: Fix H4 matrix keyboard warning Convert to use matrix keyboard to remove the warning "Please update the board to use matrix-keypad driver". Based on similar setup in palmtc.c. Note that this patch is compile tested only because of lack of working hardware. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-h4.c | 122 +++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 53 deletions(-) diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index c12666ee7017..8b351d92a1cc 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -50,10 +50,8 @@ #define H4_ETHR_GPIO_IRQ 92 -static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 }; -static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 }; - -static const unsigned int h4_keymap[] = { +#if defined(CONFIG_KEYBOARD_MATRIX) || defined(CONFIG_KEYBOARD_MATRIX_MODULE) +static const uint32_t board_matrix_keys[] = { KEY(0, 0, KEY_LEFT), KEY(1, 0, KEY_RIGHT), KEY(2, 0, KEY_A), @@ -86,6 +84,71 @@ static const unsigned int h4_keymap[] = { KEY(4, 5, KEY_ENTER), }; +static const struct matrix_keymap_data board_keymap_data = { + .keymap = board_matrix_keys, + .keymap_size = ARRAY_SIZE(board_matrix_keys), +}; + +static unsigned int board_keypad_row_gpios[] = { + 88, 89, 124, 11, 6, 96 +}; + +static unsigned int board_keypad_col_gpios[] = { + 90, 91, 100, 36, 12, 97, 98 +}; + +static struct matrix_keypad_platform_data board_keypad_platform_data = { + .keymap_data = &board_keymap_data, + .row_gpios = board_keypad_row_gpios, + .num_row_gpios = ARRAY_SIZE(board_keypad_row_gpios), + .col_gpios = board_keypad_col_gpios, + .num_col_gpios = ARRAY_SIZE(board_keypad_col_gpios), + .active_low = 1, + + .debounce_ms = 20, + .col_scan_delay_us = 5, +}; + +static struct platform_device board_keyboard = { + .name = "matrix-keypad", + .id = -1, + .dev = { + .platform_data = &board_keypad_platform_data, + }, +}; +static void __init board_mkp_init(void) +{ + omap_mux_init_gpio(88, OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_gpio(89, OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_gpio(124, OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_signal("mcbsp2_dr.gpio_11", OMAP_PULL_ENA | OMAP_PULL_UP); + if (omap_has_menelaus()) { + omap_mux_init_signal("sdrc_a14.gpio0", + OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_signal("vlynq_rx0.gpio_15", 0); + omap_mux_init_signal("gpio_98", 0); + board_keypad_row_gpios[5] = 0; + board_keypad_col_gpios[2] = 15; + board_keypad_col_gpios[6] = 18; + } else { + omap_mux_init_signal("gpio_96", OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_signal("gpio_100", 0); + omap_mux_init_signal("gpio_98", 0); + } + omap_mux_init_signal("gpio_90", 0); + omap_mux_init_signal("gpio_91", 0); + omap_mux_init_signal("gpio_36", 0); + omap_mux_init_signal("mcbsp2_clkx.gpio_12", 0); + omap_mux_init_signal("gpio_97", 0); + + platform_device_register(&board_keyboard); +} +#else +static inline void board_mkp_init(void) +{ +} +#endif + static struct mtd_partition h4_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { @@ -137,31 +200,8 @@ static struct platform_device h4_flash_device = { .resource = &h4_flash_resource, }; -static const struct matrix_keymap_data h4_keymap_data = { - .keymap = h4_keymap, - .keymap_size = ARRAY_SIZE(h4_keymap), -}; - -static struct omap_kp_platform_data h4_kp_data = { - .rows = 6, - .cols = 7, - .keymap_data = &h4_keymap_data, - .rep = true, - .row_gpios = row_gpios, - .col_gpios = col_gpios, -}; - -static struct platform_device h4_kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &h4_kp_data, - }, -}; - static struct platform_device *h4_devices[] __initdata = { &h4_flash_device, - &h4_kp_device, }; static struct panel_generic_dpi_data h4_panel_data = { @@ -336,31 +376,7 @@ static void __init omap_h4_init(void) * if not needed. */ -#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE) - omap_mux_init_gpio(88, OMAP_PULL_ENA | OMAP_PULL_UP); - omap_mux_init_gpio(89, OMAP_PULL_ENA | OMAP_PULL_UP); - omap_mux_init_gpio(124, OMAP_PULL_ENA | OMAP_PULL_UP); - omap_mux_init_signal("mcbsp2_dr.gpio_11", OMAP_PULL_ENA | OMAP_PULL_UP); - if (omap_has_menelaus()) { - omap_mux_init_signal("sdrc_a14.gpio0", - OMAP_PULL_ENA | OMAP_PULL_UP); - omap_mux_init_signal("vlynq_rx0.gpio_15", 0); - omap_mux_init_signal("gpio_98", 0); - row_gpios[5] = 0; - col_gpios[2] = 15; - col_gpios[6] = 18; - } else { - omap_mux_init_signal("gpio_96", OMAP_PULL_ENA | OMAP_PULL_UP); - omap_mux_init_signal("gpio_100", 0); - omap_mux_init_signal("gpio_98", 0); - } - omap_mux_init_signal("gpio_90", 0); - omap_mux_init_signal("gpio_91", 0); - omap_mux_init_signal("gpio_36", 0); - omap_mux_init_signal("mcbsp2_clkx.gpio_12", 0); - omap_mux_init_signal("gpio_97", 0); -#endif - + board_mkp_init(); i2c_register_board_info(1, h4_i2c_board_info, ARRAY_SIZE(h4_i2c_board_info)); From 5c8a0fbba543d9428a486f0d1282bbcf3cf1d95a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 1 Nov 2011 18:23:10 -0500 Subject: [PATCH 1479/1596] VFS: fix statfs() automounter semantics regression No one in their right mind would expect statfs() to not work on a automounter managed mount point. Fix it. [ I'm not sure about the "no one in their right mind" part. It's not mounted, and you didn't ask for it to be mounted. But nobody will really care, and this probably makes it match previous semantics, so.. - Linus ] This mirrors the fix made to the quota code in 815d405ceff0d69646. Signed-off-by: Dan McGee Cc: Trond Myklebust Cc: Alexander Viro Cc: stable@kernel.org Signed-off-by: Linus Torvalds --- fs/statfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/statfs.c b/fs/statfs.c index 8244924dec55..9cf04a118965 100644 --- a/fs/statfs.c +++ b/fs/statfs.c @@ -76,7 +76,7 @@ EXPORT_SYMBOL(vfs_statfs); int user_statfs(const char __user *pathname, struct kstatfs *st) { struct path path; - int error = user_path(pathname, &path); + int error = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path); if (!error) { error = vfs_statfs(&path, st); path_put(&path); From 1a6422f67fbf691cf8721076619aeead9183403d Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 4 Nov 2011 12:58:41 +0000 Subject: [PATCH 1480/1596] etherh: Add MAINTAINERS entry for etherh During the re-organization of Ethernet drivers, the MAINTAINERS entry for etherh got dropped accidentally. CC: Russell King CC: Joe Perches Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a6afe342f0fc..ecb2299a1601 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1032,6 +1032,7 @@ F: arch/arm/include/asm/hardware/ioc.h F: arch/arm/include/asm/hardware/iomd.h F: arch/arm/include/asm/hardware/memc.h F: arch/arm/mach-rpc/ +F: drivers/net/ethernet/8390/etherh.c F: drivers/net/ethernet/i825xx/ether1* F: drivers/net/ethernet/seeq/ether3* F: drivers/scsi/arm/ From dc822e57ee05856291a8c9324d2309076ee5f5e2 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Sat, 5 Nov 2011 11:08:54 +0900 Subject: [PATCH 1481/1596] ARM: EXYNOS4: Fix the merge conflict The mark of conflict should be removed. This happened at the commit fba9569924e0 ("Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma") Signed-off-by: Kukjin Kim [ I always check the conflict resolution with "git diff" before I add the result, but I clearly missed that this time, and didn't notice the second conflict in that file after having fixed the first one. Oops, my bad. - Linus ] Signed-off-by: Linus Torvalds --- arch/arm/mach-exynos4/clock.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c index e21952dfb7e1..a52024e309b0 100644 --- a/arch/arm/mach-exynos4/clock.c +++ b/arch/arm/mach-exynos4/clock.c @@ -1286,11 +1286,8 @@ void __init exynos4_register_clocks(void) s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); -<<<<<<< HEAD register_syscore_ops(&exynos4_clock_syscore_ops); -======= s3c24xx_register_clock(&dummy_apb_pclk); ->>>>>>> 4598fc2c94b68740e0269db03c98a1e7ad5af773 s3c_pwmclk_init(); } From d5240dfd3c80ad2fd17b25ca38d199ab1262ab6e Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 27 Oct 2011 11:33:15 +0100 Subject: [PATCH 1482/1596] ARM: PXA: fix lubbock PCMCIA driver build error Fix: ERROR: "pxa2xx_configure_sockets" [drivers/pcmcia/pxa2xx_lubbock_cs.ko] undefined! by exporting the required function. Acked-by: Eric Miao Signed-off-by: Russell King --- drivers/pcmcia/pxa2xx_base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 2c540542b5af..a87e2728b2c3 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -231,6 +231,7 @@ void pxa2xx_configure_sockets(struct device *dev) __raw_writel(mecr, MECR); } +EXPORT_SYMBOL(pxa2xx_configure_sockets); static const char *skt_names[] = { "PCMCIA socket 0", From 955d2953b0402f497d58eaea91f36486bb473008 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 27 Oct 2011 11:37:47 +0100 Subject: [PATCH 1483/1596] ARM: PXA: eseries: fix eseries_register_clks section mismatch warning Fix: WARNING: vmlinux.o(.text+0x1a820): Section mismatch in reference from the function eseries_register_clks() to the function .init.text:clkdev_add_table() The function eseries_register_clks() references the function __init clkdev_add_table(). This is often because eseries_register_clks lacks a __init annotation or the annotation of clkdev_add_table is wrong. by adding the __init annotation to eseries_register_clks() - this function is only called from other __init-marked functions. While we're here, mark it static as it's only called from within eseries.c. Acked-by: Eric Miao Signed-off-by: Russell King --- arch/arm/mach-pxa/eseries.c | 2 +- arch/arm/mach-pxa/eseries.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c index 8e697dd8accd..d82b7aa3c096 100644 --- a/arch/arm/mach-pxa/eseries.c +++ b/arch/arm/mach-pxa/eseries.c @@ -144,7 +144,7 @@ static struct clk_lookup eseries_clkregs[] = { INIT_CLKREG(&tmio_dummy_clk, NULL, "CLK_CK32K"), }; -void eseries_register_clks(void) +static void __init eseries_register_clks(void) { clkdev_add_table(eseries_clkregs, ARRAY_SIZE(eseries_clkregs)); } diff --git a/arch/arm/mach-pxa/eseries.h b/arch/arm/mach-pxa/eseries.h index be921965e91a..b96949dd5adb 100644 --- a/arch/arm/mach-pxa/eseries.h +++ b/arch/arm/mach-pxa/eseries.h @@ -11,5 +11,4 @@ extern int eseries_tmio_resume(struct platform_device *dev); extern void eseries_get_tmio_gpios(void); extern struct resource eseries_tmio_resources[]; extern struct platform_device e300_tc6387xb_device; -extern void eseries_register_clks(void); From 5895a9c0818d3c800ac8e7d3d3827cc89df2bdbf Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Fri, 14 Oct 2011 12:47:01 +0100 Subject: [PATCH 1484/1596] ARM: 7134/1: Revert "EXYNOS4: Fix routing timer interrupt to offline CPU" This reverts commit 4bd0fe1c78623062263cf5ae875fd484c5b8256d. This implementation can introduce a problem and 'ARM: SMP: fix per cpu timer setup before the cpu is marked online' patch can solve the cpu_oneline vs. cpu_active problem so that should be reverted. Signed-off-by: Kukjin Kim Signed-off-by: Russell King --- arch/arm/mach-exynos4/platsmp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c index 05595407e9ff..69ffb2fb3875 100644 --- a/arch/arm/mach-exynos4/platsmp.c +++ b/arch/arm/mach-exynos4/platsmp.c @@ -110,8 +110,6 @@ void __cpuinit platform_secondary_init(unsigned int cpu) */ spin_lock(&boot_lock); spin_unlock(&boot_lock); - - set_cpu_online(cpu, true); } int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) From 4fc7ae3c849a5a15965c1d41b59b0a606119e71a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 28 Oct 2011 15:25:01 +0100 Subject: [PATCH 1485/1596] ARM: 7142/1: davinci: mark GPIO implementation complex When breaking apart the DaVinci GPIO files I accidentally marked it non-complex while it is indeed complex. Reported-by: Mike Frysinger Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-davinci/include/mach/gpio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h index fbaae4772b91..960e9de47e1e 100644 --- a/arch/arm/mach-davinci/include/mach/gpio.h +++ b/arch/arm/mach-davinci/include/mach/gpio.h @@ -15,6 +15,8 @@ #include +#define __ARM_GPIOLIB_COMPLEX + /* The inline versions use the static inlines in the driver header */ #include "gpio-davinci.h" From cef153a8d41195f69314d93d4b2b7395e263a3a1 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 23 Aug 2011 22:30:09 +0100 Subject: [PATCH 1486/1596] watchdog: sc520_wdt: Remove unnecessary cast. Signed-off-by: Sean Young Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/sc520_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c index 52b63f2f0dac..b2840409ebc7 100644 --- a/drivers/watchdog/sc520_wdt.c +++ b/drivers/watchdog/sc520_wdt.c @@ -398,7 +398,7 @@ static int __init sc520_wdt_init(void) WATCHDOG_TIMEOUT); } - wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2); + wdtmrctl = ioremap(MMCR_BASE + OFFS_WDTMRCTL, 2); if (!wdtmrctl) { printk(KERN_ERR PFX "Unable to remap memory\n"); rc = -ENOMEM; From 47bfd058132e6da2a582b85033867ce8b9f5f331 Mon Sep 17 00:00:00 2001 From: Venkat Subbiah Date: Mon, 3 Oct 2011 17:22:04 -0700 Subject: [PATCH 1487/1596] watchdog: Octeon: Mark octeon_wdt interrupt as IRQF_NO_THREAD This is to exclude it from force threading to allow RT patch set to work. The watchdog timers are per-CPU and the addresses of register that reset the timer are calculated based on the current CPU. Therefore we cannot allow it to run on a thread on a different CPU. Also we only do a single register write, which is much faster than scheduling a handler thread. And while on this line remove IRQF_DISABLED as this flag is a NOP. Signed-off-by: Venkat Subbiah Acked-by: David Daney Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/octeon-wdt-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index 945ee8300306..7c0d8630e641 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c @@ -402,7 +402,7 @@ static void octeon_wdt_setup_interrupt(int cpu) irq = OCTEON_IRQ_WDOG0 + core; if (request_irq(irq, octeon_wdt_poke_irq, - IRQF_DISABLED, "octeon_wdt", octeon_wdt_poke_irq)) + IRQF_NO_THREAD, "octeon_wdt", octeon_wdt_poke_irq)) panic("octeon_wdt: Couldn't obtain irq %d", irq); cpumask_set_cpu(cpu, &irq_enabled_cpus); From 86b5912880453532440358b1486410ad49ef7672 Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Wed, 7 Sep 2011 16:10:55 +0800 Subject: [PATCH 1488/1596] watchdog: irq: Remove IRQF_DISABLED This flag is a NOOP and can be removed now. Signed-off-by: Yong Zhang Acked-by: Wolfram Sang Acked-by: Linus Walleij Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/coh901327_wdt.c | 2 +- drivers/watchdog/eurotechwdt.c | 2 +- drivers/watchdog/mpcore_wdt.c | 3 +-- drivers/watchdog/sb_wdog.c | 4 ++-- drivers/watchdog/wdt.c | 2 +- drivers/watchdog/wdt_pci.c | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index 9291506b8b23..03f449a430d2 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -429,7 +429,7 @@ static int __init coh901327_probe(struct platform_device *pdev) writew(U300_WDOG_SR_RESET_STATUS_RESET, virtbase + U300_WDOG_SR); irq = platform_get_irq(pdev, 0); - if (request_irq(irq, coh901327_interrupt, IRQF_DISABLED, + if (request_irq(irq, coh901327_interrupt, 0, DRV_NAME " Bark", pdev)) { ret = -EIO; goto out_no_irq; diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c index f1d1da662fbe..41018d429abb 100644 --- a/drivers/watchdog/eurotechwdt.c +++ b/drivers/watchdog/eurotechwdt.c @@ -427,7 +427,7 @@ static int __init eurwdt_init(void) { int ret; - ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); + ret = request_irq(irq, eurwdt_interrupt, 0, "eurwdt", NULL); if (ret) { printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); goto out; diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c index 4dc31024d26c..82ccd36e2c90 100644 --- a/drivers/watchdog/mpcore_wdt.c +++ b/drivers/watchdog/mpcore_wdt.c @@ -367,8 +367,7 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev) goto err_misc; } - ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED, - "mpcore_wdt", wdt); + ret = request_irq(wdt->irq, mpcore_wdt_fire, 0, "mpcore_wdt", wdt); if (ret) { dev_printk(KERN_ERR, wdt->dev, "cannot register IRQ%d for watchdog\n", wdt->irq); diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c index f31493e65b38..b01a30e5a663 100644 --- a/drivers/watchdog/sb_wdog.c +++ b/drivers/watchdog/sb_wdog.c @@ -300,7 +300,7 @@ static int __init sbwdog_init(void) * get the resources */ - ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, + ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED, ident.identity, (void *)user_dog); if (ret) { printk(KERN_ERR "%s: failed to request irq 1 - %d\n", @@ -350,7 +350,7 @@ void platform_wd_setup(void) { int ret; - ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, + ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED, "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0)); if (ret) { printk(KERN_CRIT diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index bb03e151a1d0..d2ef002be96b 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c @@ -612,7 +612,7 @@ static int __init wdt_init(void) goto out; } - ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL); + ret = request_irq(irq, wdt_interrupt, 0, "wdt501p", NULL); if (ret) { printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); goto outreg; diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index 172dad6c7693..e0fc3baa9197 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c @@ -643,7 +643,7 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev, irq = dev->irq; io = pci_resource_start(dev, 2); - if (request_irq(irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED, + if (request_irq(irq, wdtpci_interrupt, IRQF_SHARED, "wdt_pci", &wdtpci_miscdev)) { printk(KERN_ERR PFX "IRQ %d is not free\n", irq); goto out_reg; From c63b6d02be22899a5c8d47b8ee40e0534cd01a43 Mon Sep 17 00:00:00 2001 From: Greg Lee Date: Mon, 12 Sep 2011 20:28:46 -0400 Subject: [PATCH 1489/1596] watchdog: Add WDIOC_GETTIMELEFT ioctl support to w83627 watchdog driver Add WDIOC_GETTIMELEFT ioctl allowing you to check how much time is left on the watchdog counter before a reset occurs. Signed-off-by: Greg Lee Signed-off-by: Padraig Brady Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/watchdog/w83627hf_wdt.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index e5c91d4404ed..dd5d67548758 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -142,7 +142,7 @@ static void w83627hf_init(void) w83627hf_unselect_wd_register(); } -static void wdt_ctrl(int timeout) +static void wdt_set_time(int timeout) { spin_lock(&io_lock); @@ -158,13 +158,13 @@ static void wdt_ctrl(int timeout) static int wdt_ping(void) { - wdt_ctrl(timeout); + wdt_set_time(timeout); return 0; } static int wdt_disable(void) { - wdt_ctrl(0); + wdt_set_time(0); return 0; } @@ -176,6 +176,24 @@ static int wdt_set_heartbeat(int t) return 0; } +static int wdt_get_time(void) +{ + int timeleft; + + spin_lock(&io_lock); + + w83627hf_select_wd_register(); + + outb_p(0xF6, WDT_EFER); /* Select CRF6 */ + timeleft = inb_p(WDT_EFDR); /* Read Timeout counter to CRF6 */ + + w83627hf_unselect_wd_register(); + + spin_unlock(&io_lock); + + return timeleft; +} + static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -202,7 +220,7 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; int __user *p = argp; - int new_timeout; + int timeval; static const struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, @@ -238,14 +256,17 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) wdt_ping(); break; case WDIOC_SETTIMEOUT: - if (get_user(new_timeout, p)) + if (get_user(timeval, p)) return -EFAULT; - if (wdt_set_heartbeat(new_timeout)) + if (wdt_set_heartbeat(timeval)) return -EINVAL; wdt_ping(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timeout, p); + case WDIOC_GETTIMELEFT: + timeval = wdt_get_time(); + return put_user(timeval, p); default: return -ENOTTY; } From deb9197b7031b8f4ed311dc47a14363da4458544 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Wed, 19 Oct 2011 23:59:26 +0200 Subject: [PATCH 1490/1596] watchdog: iTCO_wdt.c - problems with newer hardware due to SMI clearing Redhat Bugzilla: Bug 727875 - TCO_EN bit is disabled by TCO driver Jiri Slaby: 28d41f53f broke temperature sensors on a ICH10 chipset The iTCO_wdt driver disables the SMI. This breaks good working of newer hardware. The disabling of the SMI by the TCO logic dates back from the i810-tco driver from Nils Faerber (around 28 July 2000). The reason for this was that some BIOSes install handlers reset or disable the watchdog timer instead of resetting the system. The trick to fix this was to disable the SMI (by clearing the SMI_TCO_EN bit of the SMI_EN register) to prevent this from happening. This however has strange effects on newer hardware. So we are in a situation that a fix for broken old hardware affects newer hardware. The correct solution is to make this fix an option (with the new module parameter: turn_SMI_watchdog_clear_off) so that the default behaviour is the unfixed version. the next patch will be to move this in the start and stop functions of the driver and to add a new module parameter for the global_smi_en bit and to get rid of the vendor_support code. This fix can have an effect on old (typical ICH & ICH2 chipsets) motherboards that have a broken BIOS implementation concerning TCO logic. In these case the module parameter turn_SMI_watchdog_clear_off=1 will need to be added. Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/iTCO_wdt.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 751a591684da..ba6ad662635a 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -1,7 +1,7 @@ /* * intel TCO Watchdog Driver * - * (c) Copyright 2006-2010 Wim Van Sebroeck . + * (c) Copyright 2006-2011 Wim Van Sebroeck . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -44,7 +44,7 @@ /* Module and version information */ #define DRV_NAME "iTCO_wdt" -#define DRV_VERSION "1.06" +#define DRV_VERSION "1.07" #define PFX DRV_NAME ": " /* Includes */ @@ -384,6 +384,11 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +static int turn_SMI_watchdog_clear_off = 0; +module_param(turn_SMI_watchdog_clear_off, int, 0); +MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, + "Turn off SMI clearing watchdog (default=0)"); + /* * Some TCO specific functions */ @@ -808,10 +813,12 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, ret = -EIO; goto out_unmap; } - /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ - val32 = inl(SMI_EN); - val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ - outl(val32, SMI_EN); + if (turn_SMI_watchdog_clear_off) { + /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ + val32 = inl(SMI_EN); + val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ + outl(val32, SMI_EN); + } /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */ From 74cd4c67392c1cee0499ba0977ec843252c7af28 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 26 Sep 2011 15:40:13 +0200 Subject: [PATCH 1491/1596] Documentation: watchdog: add guide how to convert drivers to new framework Signed-off-by: Wolfram Sang Cc: Randy Dunlap Signed-off-by: Wim Van Sebroeck --- .../convert_drivers_to_kernel_api.txt | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 Documentation/watchdog/convert_drivers_to_kernel_api.txt diff --git a/Documentation/watchdog/convert_drivers_to_kernel_api.txt b/Documentation/watchdog/convert_drivers_to_kernel_api.txt new file mode 100644 index 000000000000..ae1e90036d06 --- /dev/null +++ b/Documentation/watchdog/convert_drivers_to_kernel_api.txt @@ -0,0 +1,195 @@ +Converting old watchdog drivers to the watchdog framework +by Wolfram Sang +========================================================= + +Before the watchdog framework came into the kernel, every driver had to +implement the API on its own. Now, as the framework factored out the common +components, those drivers can be lightened making it a user of the framework. +This document shall guide you for this task. The necessary steps are described +as well as things to look out for. + + +Remove the file_operations struct +--------------------------------- + +Old drivers define their own file_operations for actions like open(), write(), +etc... These are now handled by the framework and just call the driver when +needed. So, in general, the 'file_operations' struct and assorted functions can +go. Only very few driver-specific details have to be moved to other functions. +Here is a overview of the functions and probably needed actions: + +- open: Everything dealing with resource management (file-open checks, magic + close preparations) can simply go. Device specific stuff needs to go to the + driver specific start-function. Note that for some drivers, the start-function + also serves as the ping-function. If that is the case and you need start/stop + to be balanced (clocks!), you are better off refactoring a separate start-function. + +- close: Same hints as for open apply. + +- write: Can simply go, all defined behaviour is taken care of by the framework, + i.e. ping on write and magic char ('V') handling. + +- ioctl: While the driver is allowed to have extensions to the IOCTL interface, + the most common ones are handled by the framework, supported by some assistance + from the driver: + + WDIOC_GETSUPPORT: + Returns the mandatory watchdog_info struct from the driver + + WDIOC_GETSTATUS: + Needs the status-callback defined, otherwise returns 0 + + WDIOC_GETBOOTSTATUS: + Needs the bootstatus member properly set. Make sure it is 0 if you + don't have further support! + + WDIOC_SETOPTIONS: + No preparations needed + + WDIOC_KEEPALIVE: + If wanted, options in watchdog_info need to have WDIOF_KEEPALIVEPING + set + + WDIOC_SETTIMEOUT: + Options in watchdog_info need to have WDIOF_SETTIMEOUT set + and a set_timeout-callback has to be defined. The core will also + do limit-checking, if min_timeout and max_timeout in the watchdog + device are set. All is optional. + + WDIOC_GETTIMEOUT: + No preparations needed + + Other IOCTLs can be served using the ioctl-callback. Note that this is mainly + intended for porting old drivers; new drivers should not invent private IOCTLs. + Private IOCTLs are processed first. When the callback returns with + -ENOIOCTLCMD, the IOCTLs of the framework will be tried, too. Any other error + is directly given to the user. + +Example conversion: + +-static const struct file_operations s3c2410wdt_fops = { +- .owner = THIS_MODULE, +- .llseek = no_llseek, +- .write = s3c2410wdt_write, +- .unlocked_ioctl = s3c2410wdt_ioctl, +- .open = s3c2410wdt_open, +- .release = s3c2410wdt_release, +-}; + +Check the functions for device-specific stuff and keep it for later +refactoring. The rest can go. + + +Remove the miscdevice +--------------------- + +Since the file_operations are gone now, you can also remove the 'struct +miscdevice'. The framework will create it on watchdog_dev_register() called by +watchdog_register_device(). + +-static struct miscdevice s3c2410wdt_miscdev = { +- .minor = WATCHDOG_MINOR, +- .name = "watchdog", +- .fops = &s3c2410wdt_fops, +-}; + + +Remove obsolete includes and defines +------------------------------------ + +Because of the simplifications, a few defines are probably unused now. Remove +them. Includes can be removed, too. For example: + +- #include +- #include (if MODULE_ALIAS_MISCDEV is not used) +- #include (if no custom IOCTLs are used) + + +Add the watchdog operations +--------------------------- + +All possible callbacks are defined in 'struct watchdog_ops'. You can find it +explained in 'watchdog-kernel-api.txt' in this directory. start(), stop() and +owner must be set, the rest are optional. You will easily find corresponding +functions in the old driver. Note that you will now get a pointer to the +watchdog_device as a parameter to these functions, so you probably have to +change the function header. Other changes are most likely not needed, because +here simply happens the direct hardware access. If you have device-specific +code left from the above steps, it should be refactored into these callbacks. + +Here is a simple example: + ++static struct watchdog_ops s3c2410wdt_ops = { ++ .owner = THIS_MODULE, ++ .start = s3c2410wdt_start, ++ .stop = s3c2410wdt_stop, ++ .ping = s3c2410wdt_keepalive, ++ .set_timeout = s3c2410wdt_set_heartbeat, ++}; + +A typical function-header change looks like: + +-static void s3c2410wdt_keepalive(void) ++static int s3c2410wdt_keepalive(struct watchdog_device *wdd) + { +... ++ ++ return 0; + } + +... + +- s3c2410wdt_keepalive(); ++ s3c2410wdt_keepalive(&s3c2410_wdd); + + +Add the watchdog device +----------------------- + +Now we need to create a 'struct watchdog_device' and populate it with the +necessary information for the framework. The struct is also explained in detail +in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory +watchdog_info struct and the newly created watchdog_ops. Often, old drivers +have their own record-keeping for things like bootstatus and timeout using +static variables. Those have to be converted to use the members in +watchdog_device. Note that the timeout values are unsigned int. Some drivers +use signed int, so this has to be converted, too. + +Here is a simple example for a watchdog device: + ++static struct watchdog_device s3c2410_wdd = { ++ .info = &s3c2410_wdt_ident, ++ .ops = &s3c2410wdt_ops, ++}; + + +Register the watchdog device +---------------------------- + +Replace misc_register(&miscdev) with watchdog_register_device(&watchdog_dev). +Make sure the return value gets checked and the error message, if present, +still fits. Also convert the unregister case. + +- ret = misc_register(&s3c2410wdt_miscdev); ++ ret = watchdog_register_device(&s3c2410_wdd); + +... + +- misc_deregister(&s3c2410wdt_miscdev); ++ watchdog_unregister_device(&s3c2410_wdd); + + +Update the Kconfig-entry +------------------------ + +The entry for the driver now needs to select WATCHDOG_CORE: + ++ select WATCHDOG_CORE + + +Create a patch and send it to upstream +-------------------------------------- + +Make sure you understood Documentation/SubmittingPatches and send your patch to +linux-watchdog@vger.kernel.org. We are looking forward to it :) + From 25dc46e3837cd01dc1742eefb73d064f6336850f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 26 Sep 2011 15:40:14 +0200 Subject: [PATCH 1492/1596] watchdog: s3c2410: convert to use the watchdog framework Make this driver a user of the watchdog framework and remove now centrally handled parts. Tested on a mini2440. Signed-off-by: Wolfram Sang Acked-by: Kukjin Kim Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 1 + drivers/watchdog/s3c2410_wdt.c | 176 +++++++-------------------------- 2 files changed, 38 insertions(+), 139 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 64c6752ea2c6..40a36c50a5f4 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -170,6 +170,7 @@ config HAVE_S3C2410_WATCHDOG config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG + select WATCHDOG_CORE help Watchdog timer block in the Samsung SoCs. This will reboot the system when the timer expires with the watchdog enabled. diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 30da88f47cd3..5de7e4fa5b8a 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -27,9 +27,8 @@ #include #include #include -#include +#include /* for MODULE_ALIAS_MISCDEV */ #include -#include #include #include #include @@ -38,6 +37,7 @@ #include #include #include +#include #include @@ -74,14 +74,12 @@ MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " "0 to reboot (default 0)"); MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); -static unsigned long open_lock; static struct device *wdt_dev; /* platform device attached to */ static struct resource *wdt_mem; static struct resource *wdt_irq; static struct clk *wdt_clock; static void __iomem *wdt_base; static unsigned int wdt_count; -static char expect_close; static DEFINE_SPINLOCK(wdt_lock); /* watchdog control routines */ @@ -93,11 +91,13 @@ static DEFINE_SPINLOCK(wdt_lock); /* functions */ -static void s3c2410wdt_keepalive(void) +static int s3c2410wdt_keepalive(struct watchdog_device *wdd) { spin_lock(&wdt_lock); writel(wdt_count, wdt_base + S3C2410_WTCNT); spin_unlock(&wdt_lock); + + return 0; } static void __s3c2410wdt_stop(void) @@ -109,14 +109,16 @@ static void __s3c2410wdt_stop(void) writel(wtcon, wdt_base + S3C2410_WTCON); } -static void s3c2410wdt_stop(void) +static int s3c2410wdt_stop(struct watchdog_device *wdd) { spin_lock(&wdt_lock); __s3c2410wdt_stop(); spin_unlock(&wdt_lock); + + return 0; } -static void s3c2410wdt_start(void) +static int s3c2410wdt_start(struct watchdog_device *wdd) { unsigned long wtcon; @@ -142,6 +144,8 @@ static void s3c2410wdt_start(void) writel(wdt_count, wdt_base + S3C2410_WTCNT); writel(wtcon, wdt_base + S3C2410_WTCON); spin_unlock(&wdt_lock); + + return 0; } static inline int s3c2410wdt_is_running(void) @@ -149,7 +153,7 @@ static inline int s3c2410wdt_is_running(void) return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; } -static int s3c2410wdt_set_heartbeat(int timeout) +static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout) { unsigned long freq = clk_get_rate(wdt_clock); unsigned int count; @@ -182,8 +186,6 @@ static int s3c2410wdt_set_heartbeat(int timeout) } } - tmr_margin = timeout; - DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", __func__, timeout, divisor, count, count/divisor); @@ -201,70 +203,6 @@ static int s3c2410wdt_set_heartbeat(int timeout) return 0; } -/* - * /dev/watchdog handling - */ - -static int s3c2410wdt_open(struct inode *inode, struct file *file) -{ - if (test_and_set_bit(0, &open_lock)) - return -EBUSY; - - if (nowayout) - __module_get(THIS_MODULE); - - expect_close = 0; - - /* start the timer */ - s3c2410wdt_start(); - return nonseekable_open(inode, file); -} - -static int s3c2410wdt_release(struct inode *inode, struct file *file) -{ - /* - * Shut off the timer. - * Lock it in if it's a module and we set nowayout - */ - - if (expect_close == 42) - s3c2410wdt_stop(); - else { - dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n"); - s3c2410wdt_keepalive(); - } - expect_close = 0; - clear_bit(0, &open_lock); - return 0; -} - -static ssize_t s3c2410wdt_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - /* - * Refresh the timer. - */ - if (len) { - if (!nowayout) { - size_t i; - - /* In case it was set long ago */ - expect_close = 0; - - for (i = 0; i != len; i++) { - char c; - - if (get_user(c, data + i)) - return -EFAULT; - if (c == 'V') - expect_close = 42; - } - } - s3c2410wdt_keepalive(); - } - return len; -} - #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) static const struct watchdog_info s3c2410_wdt_ident = { @@ -273,53 +211,17 @@ static const struct watchdog_info s3c2410_wdt_ident = { .identity = "S3C2410 Watchdog", }; - -static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int __user *p = argp; - int new_margin; - - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &s3c2410_wdt_ident, - sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_KEEPALIVE: - s3c2410wdt_keepalive(); - return 0; - case WDIOC_SETTIMEOUT: - if (get_user(new_margin, p)) - return -EFAULT; - if (s3c2410wdt_set_heartbeat(new_margin)) - return -EINVAL; - s3c2410wdt_keepalive(); - return put_user(tmr_margin, p); - case WDIOC_GETTIMEOUT: - return put_user(tmr_margin, p); - default: - return -ENOTTY; - } -} - -/* kernel interface */ - -static const struct file_operations s3c2410wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = s3c2410wdt_write, - .unlocked_ioctl = s3c2410wdt_ioctl, - .open = s3c2410wdt_open, - .release = s3c2410wdt_release, +static struct watchdog_ops s3c2410wdt_ops = { + .owner = THIS_MODULE, + .start = s3c2410wdt_start, + .stop = s3c2410wdt_stop, + .ping = s3c2410wdt_keepalive, + .set_timeout = s3c2410wdt_set_heartbeat, }; -static struct miscdevice s3c2410wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &s3c2410wdt_fops, +static struct watchdog_device s3c2410_wdd = { + .info = &s3c2410_wdt_ident, + .ops = &s3c2410wdt_ops, }; /* interrupt handler code */ @@ -328,7 +230,7 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) { dev_info(wdt_dev, "watchdog timer expired (irq)\n"); - s3c2410wdt_keepalive(); + s3c2410wdt_keepalive(&s3c2410_wdd); return IRQ_HANDLED; } @@ -349,14 +251,14 @@ static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, * the watchdog is running. */ - s3c2410wdt_keepalive(); + s3c2410wdt_keepalive(&s3c2410_wdd); } else if (val == CPUFREQ_POSTCHANGE) { - s3c2410wdt_stop(); + s3c2410wdt_stop(&s3c2410_wdd); - ret = s3c2410wdt_set_heartbeat(tmr_margin); + ret = s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout); if (ret >= 0) - s3c2410wdt_start(); + s3c2410wdt_start(&s3c2410_wdd); else goto err; } @@ -365,7 +267,8 @@ static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, return 0; err: - dev_err(wdt_dev, "cannot set new value for timeout %d\n", tmr_margin); + dev_err(wdt_dev, "cannot set new value for timeout %d\n", + s3c2410_wdd.timeout); return ret; } @@ -396,10 +299,6 @@ static inline void s3c2410wdt_cpufreq_deregister(void) } #endif - - -/* device interface */ - static int __devinit s3c2410wdt_probe(struct platform_device *pdev) { struct device *dev; @@ -466,8 +365,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) /* see if we can actually set the requested timer margin, and if * not, try the default value */ - if (s3c2410wdt_set_heartbeat(tmr_margin)) { - started = s3c2410wdt_set_heartbeat( + if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, tmr_margin)) { + started = s3c2410wdt_set_heartbeat(&s3c2410_wdd, CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); if (started == 0) @@ -479,22 +378,21 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) "cannot start\n"); } - ret = misc_register(&s3c2410wdt_miscdev); + ret = watchdog_register_device(&s3c2410_wdd); if (ret) { - dev_err(dev, "cannot register miscdev on minor=%d (%d)\n", - WATCHDOG_MINOR, ret); + dev_err(dev, "cannot register watchdog (%d)\n", ret); goto err_cpufreq; } if (tmr_atboot && started == 0) { dev_info(dev, "starting watchdog timer\n"); - s3c2410wdt_start(); + s3c2410wdt_start(&s3c2410_wdd); } else if (!tmr_atboot) { /* if we're not enabling the watchdog, then ensure it is * disabled if it has been left running from the bootloader * or other source */ - s3c2410wdt_stop(); + s3c2410wdt_stop(&s3c2410_wdd); } /* print out a statement of readiness */ @@ -530,7 +428,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) static int __devexit s3c2410wdt_remove(struct platform_device *dev) { - misc_deregister(&s3c2410wdt_miscdev); + watchdog_unregister_device(&s3c2410_wdd); s3c2410wdt_cpufreq_deregister(); @@ -550,7 +448,7 @@ static int __devexit s3c2410wdt_remove(struct platform_device *dev) static void s3c2410wdt_shutdown(struct platform_device *dev) { - s3c2410wdt_stop(); + s3c2410wdt_stop(&s3c2410_wdd); } #ifdef CONFIG_PM @@ -565,7 +463,7 @@ static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state) wtdat_save = readl(wdt_base + S3C2410_WTDAT); /* Note that WTCNT doesn't need to be saved. */ - s3c2410wdt_stop(); + s3c2410wdt_stop(&s3c2410_wdd); return 0; } From 00411ee9308e4b5f4b04caaa01685f955e259373 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 4 Oct 2011 16:43:40 +0100 Subject: [PATCH 1493/1596] watchdog: Convert wm831x driver to watchdog core Fairly large code churn but not much doing with that and the overall result is a definite win. Signed-off-by: Mark Brown Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 1 + drivers/watchdog/wm831x_wdt.c | 318 +++++++++++----------------------- 2 files changed, 106 insertions(+), 213 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 40a36c50a5f4..6285867a9356 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -66,6 +66,7 @@ config SOFT_WATCHDOG config WM831X_WATCHDOG tristate "WM831x watchdog" depends on MFD_WM831X + select WATCHDOG_CORE help Support for the watchdog in the WM831x AudioPlus PMICs. When the watchdog triggers the system will be reset. diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 871caea4e1c6..7be38556aed0 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c @@ -12,8 +12,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -29,19 +28,19 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -static unsigned long wm831x_wdt_users; -static struct miscdevice wm831x_wdt_miscdev; -static int wm831x_wdt_expect_close; -static DEFINE_MUTEX(wdt_mutex); -static struct wm831x *wm831x; -static unsigned int update_gpio; -static unsigned int update_state; +struct wm831x_wdt_drvdata { + struct watchdog_device wdt; + struct wm831x *wm831x; + struct mutex lock; + int update_gpio; + int update_state; +}; /* We can't use the sub-second values here but they're included * for completeness. */ static struct { - int time; /* Seconds */ - u16 val; /* WDOG_TO value */ + unsigned int time; /* Seconds */ + u16 val; /* WDOG_TO value */ } wm831x_wdt_cfgs[] = { { 1, 2 }, { 2, 3 }, @@ -52,32 +51,13 @@ static struct { { 33, 7 }, /* Actually 32.768s so include both, others round down */ }; -static int wm831x_wdt_set_timeout(struct wm831x *wm831x, u16 value) -{ - int ret; - - mutex_lock(&wdt_mutex); - - ret = wm831x_reg_unlock(wm831x); - if (ret == 0) { - ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, - WM831X_WDOG_TO_MASK, value); - wm831x_reg_lock(wm831x); - } else { - dev_err(wm831x->dev, "Failed to unlock security key: %d\n", - ret); - } - - mutex_unlock(&wdt_mutex); - - return ret; -} - -static int wm831x_wdt_start(struct wm831x *wm831x) +static int wm831x_wdt_start(struct watchdog_device *wdt_dev) { + struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); + struct wm831x *wm831x = driver_data->wm831x; int ret; - mutex_lock(&wdt_mutex); + mutex_lock(&driver_data->lock); ret = wm831x_reg_unlock(wm831x); if (ret == 0) { @@ -89,16 +69,18 @@ static int wm831x_wdt_start(struct wm831x *wm831x) ret); } - mutex_unlock(&wdt_mutex); + mutex_unlock(&driver_data->lock); return ret; } -static int wm831x_wdt_stop(struct wm831x *wm831x) +static int wm831x_wdt_stop(struct watchdog_device *wdt_dev) { + struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); + struct wm831x *wm831x = driver_data->wm831x; int ret; - mutex_lock(&wdt_mutex); + mutex_lock(&driver_data->lock); ret = wm831x_reg_unlock(wm831x); if (ret == 0) { @@ -110,26 +92,28 @@ static int wm831x_wdt_stop(struct wm831x *wm831x) ret); } - mutex_unlock(&wdt_mutex); + mutex_unlock(&driver_data->lock); return ret; } -static int wm831x_wdt_kick(struct wm831x *wm831x) +static int wm831x_wdt_ping(struct watchdog_device *wdt_dev) { + struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); + struct wm831x *wm831x = driver_data->wm831x; int ret; u16 reg; - mutex_lock(&wdt_mutex); + mutex_lock(&driver_data->lock); - if (update_gpio) { - gpio_set_value_cansleep(update_gpio, update_state); - update_state = !update_state; + if (driver_data->update_gpio) { + gpio_set_value_cansleep(driver_data->update_gpio, + driver_data->update_state); + driver_data->update_state = !driver_data->update_state; ret = 0; goto out; } - reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (!(reg & WM831X_WDOG_RST_SRC)) { @@ -150,182 +134,59 @@ static int wm831x_wdt_kick(struct wm831x *wm831x) } out: - mutex_unlock(&wdt_mutex); + mutex_unlock(&driver_data->lock); return ret; } -static int wm831x_wdt_open(struct inode *inode, struct file *file) +static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int timeout) { - int ret; - - if (!wm831x) - return -ENODEV; - - if (test_and_set_bit(0, &wm831x_wdt_users)) - return -EBUSY; + struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); + struct wm831x *wm831x = driver_data->wm831x; + int ret, i; - ret = wm831x_wdt_start(wm831x); - if (ret != 0) - return ret; - - return nonseekable_open(inode, file); -} + for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) + if (wm831x_wdt_cfgs[i].time == timeout) + break; + if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) + ret = -EINVAL; -static int wm831x_wdt_release(struct inode *inode, struct file *file) -{ - if (wm831x_wdt_expect_close) - wm831x_wdt_stop(wm831x); - else { - dev_warn(wm831x->dev, "Watchdog device closed uncleanly\n"); - wm831x_wdt_kick(wm831x); + ret = wm831x_reg_unlock(wm831x); + if (ret == 0) { + ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, + WM831X_WDOG_TO_MASK, + wm831x_wdt_cfgs[i].val); + wm831x_reg_lock(wm831x); + } else { + dev_err(wm831x->dev, "Failed to unlock security key: %d\n", + ret); } - clear_bit(0, &wm831x_wdt_users); - - return 0; -} - -static ssize_t wm831x_wdt_write(struct file *file, - const char __user *data, size_t count, - loff_t *ppos) -{ - size_t i; - - if (count) { - wm831x_wdt_kick(wm831x); - - if (!nowayout) { - /* In case it was set long ago */ - wm831x_wdt_expect_close = 0; - - /* scan to see whether or not we got the magic - character */ - for (i = 0; i != count; i++) { - char c; - if (get_user(c, data + i)) - return -EFAULT; - if (c == 'V') - wm831x_wdt_expect_close = 42; - } - } - } - return count; + return ret; } -static const struct watchdog_info ident = { +static const struct watchdog_info wm831x_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "WM831x Watchdog", }; -static long wm831x_wdt_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret = -ENOTTY, time, i; - void __user *argp = (void __user *)arg; - int __user *p = argp; - u16 reg; - - switch (cmd) { - case WDIOC_GETSUPPORT: - ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; - break; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - ret = put_user(0, p); - break; - - case WDIOC_SETOPTIONS: - { - int options; - - if (get_user(options, p)) - return -EFAULT; - - ret = -EINVAL; - - /* Setting both simultaneously means at least one must fail */ - if (options == WDIOS_DISABLECARD) - ret = wm831x_wdt_start(wm831x); - - if (options == WDIOS_ENABLECARD) - ret = wm831x_wdt_stop(wm831x); - break; - } - - case WDIOC_KEEPALIVE: - ret = wm831x_wdt_kick(wm831x); - break; - - case WDIOC_SETTIMEOUT: - ret = get_user(time, p); - if (ret) - break; - - if (time == 0) { - if (nowayout) - ret = -EINVAL; - else - wm831x_wdt_stop(wm831x); - break; - } - - for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) - if (wm831x_wdt_cfgs[i].time == time) - break; - if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) - ret = -EINVAL; - else - ret = wm831x_wdt_set_timeout(wm831x, - wm831x_wdt_cfgs[i].val); - break; - - case WDIOC_GETTIMEOUT: - reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); - reg &= WM831X_WDOG_TO_MASK; - for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) - if (wm831x_wdt_cfgs[i].val == reg) - break; - if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) { - dev_warn(wm831x->dev, - "Unknown watchdog configuration: %x\n", reg); - ret = -EINVAL; - } else - ret = put_user(wm831x_wdt_cfgs[i].time, p); - - } - - return ret; -} - -static const struct file_operations wm831x_wdt_fops = { +static const struct watchdog_ops wm831x_wdt_ops = { .owner = THIS_MODULE, - .llseek = no_llseek, - .write = wm831x_wdt_write, - .unlocked_ioctl = wm831x_wdt_ioctl, - .open = wm831x_wdt_open, - .release = wm831x_wdt_release, -}; - -static struct miscdevice wm831x_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &wm831x_wdt_fops, + .start = wm831x_wdt_start, + .stop = wm831x_wdt_stop, + .ping = wm831x_wdt_ping, + .set_timeout = wm831x_wdt_set_timeout, }; static int __devinit wm831x_wdt_probe(struct platform_device *pdev) { + struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *chip_pdata; struct wm831x_watchdog_pdata *pdata; - int reg, ret; - - if (wm831x) { - dev_err(&pdev->dev, "wm831x watchdog already registered\n"); - return -EBUSY; - } - - wm831x = dev_get_drvdata(pdev->dev.parent); + struct wm831x_wdt_drvdata *driver_data; + struct watchdog_device *wm831x_wdt; + int reg, ret, i; ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); if (ret < 0) { @@ -338,6 +199,36 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) if (reg & WM831X_WDOG_DEBUG) dev_warn(wm831x->dev, "Watchdog is paused\n"); + driver_data = kzalloc(sizeof(*driver_data), GFP_KERNEL); + if (!driver_data) { + dev_err(wm831x->dev, "Unable to alloacate watchdog device\n"); + ret = -ENOMEM; + goto err; + } + + mutex_init(&driver_data->lock); + driver_data->wm831x = wm831x; + + wm831x_wdt = &driver_data->wdt; + + wm831x_wdt->info = &wm831x_wdt_info; + wm831x_wdt->ops = &wm831x_wdt_ops; + watchdog_set_drvdata(wm831x_wdt, driver_data); + + if (nowayout) + wm831x_wdt->status |= WDOG_NO_WAY_OUT; + + reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); + reg &= WM831X_WDOG_TO_MASK; + for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) + if (wm831x_wdt_cfgs[i].val == reg) + break; + if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) + dev_warn(wm831x->dev, + "Unknown watchdog timeout: %x\n", reg); + else + wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time; + /* Apply any configuration */ if (pdev->dev.parent->platform_data) { chip_pdata = pdev->dev.parent->platform_data; @@ -361,7 +252,7 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) dev_err(wm831x->dev, "Failed to request update GPIO: %d\n", ret); - goto err; + goto err_alloc; } ret = gpio_direction_output(pdata->update_gpio, 0); @@ -372,7 +263,7 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) goto err_gpio; } - update_gpio = pdata->update_gpio; + driver_data->update_gpio = pdata->update_gpio; /* Make sure the watchdog takes hardware updates */ reg |= WM831X_WDOG_RST_SRC; @@ -389,33 +280,34 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) } } - wm831x_wdt_miscdev.parent = &pdev->dev; - - ret = misc_register(&wm831x_wdt_miscdev); + ret = watchdog_register_device(&driver_data->wdt); if (ret != 0) { - dev_err(wm831x->dev, "Failed to register miscdev: %d\n", ret); + dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", + ret); goto err_gpio; } + dev_set_drvdata(&pdev->dev, driver_data); + return 0; err_gpio: - if (update_gpio) { - gpio_free(update_gpio); - update_gpio = 0; - } + if (driver_data->update_gpio) + gpio_free(driver_data->update_gpio); +err_alloc: + kfree(driver_data); err: return ret; } static int __devexit wm831x_wdt_remove(struct platform_device *pdev) { - if (update_gpio) { - gpio_free(update_gpio); - update_gpio = 0; - } + struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev); + + watchdog_unregister_device(&driver_data->wdt); - misc_deregister(&wm831x_wdt_miscdev); + if (driver_data->update_gpio) + gpio_free(driver_data->update_gpio); return 0; } From 7124cb96cadc5f9990ade39780b672b01bfc6484 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 5 Nov 2011 22:03:25 +0000 Subject: [PATCH 1494/1596] ARM: PXA: fix gpio-pxa.h build errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A mismerge in 43872fa (Merge branch 'depends/rmk/gpio' into next/fixes) causes these build errors: In file included from arch/arm/mach-pxa/include/mach/gpio.h:30, from arch/arm/include/asm/gpio.h:6, from include/linux/gpio.h:31, from arch/arm/mach-pxa/generic.c:20: arch/arm/mach-pxa/include/mach/gpio-pxa.h: In function ■__gpio_is_occupied■: arch/arm/mach-pxa/include/mach/gpio-pxa.h:121: error: invalid operands to binary >> (have ■void *■ and ■unsigned int■) arch/arm/mach-pxa/include/mach/gpio-pxa.h:122: error: invalid operands to binary & (have ■void *■ and ■int■) arch/arm/mach-pxa/include/mach/gpio-pxa.h:129: error: invalid operands to binary & (have ■void *■ and ■int■) So fix them. Acked-by: Arnd Bergmann Signed-off-by: Russell King --- arch/arm/mach-pxa/include/mach/gpio-pxa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-pxa/include/mach/gpio-pxa.h b/arch/arm/mach-pxa/include/mach/gpio-pxa.h index 576868f8b8c5..41b4c93a96c2 100644 --- a/arch/arm/mach-pxa/include/mach/gpio-pxa.h +++ b/arch/arm/mach-pxa/include/mach/gpio-pxa.h @@ -25,7 +25,7 @@ #define GPIO_REGS_VIRT io_p2v(0x40E00000) #define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) -#define GPIO_REG(x) (GPIO_REGS_VIRT + (x)) +#define GPIO_REG(x) (*(volatile u32 *)(GPIO_REGS_VIRT + (x))) /* GPIO Pin Level Registers */ #define GPLR0 GPIO_REG(BANK_OFF(0) + 0x00) From 7a3f8de5a3c36e5fde130cae74a06663b59837ae Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 5 Nov 2011 22:06:17 +0000 Subject: [PATCH 1495/1596] ARM: PXA: fix includes in pxa2xx_cm_x2xx PCMCIA driver The includes in the pxa2xx_cm_x2xx PCMCIA driver are rather random; the driver doesn't require anything from these headers except the cpu_is_xxx() macros which come from another include. The concern is that it's getting these definitions via mach/system.h, which is supposed to only be included by arch/arm/kernel/process.c. As this header is scheduled for cleanup (and elimination) keeping the status quo will cause build errors. So lets fix properly and independent of the future work. Signed-off-by: Russell King --- drivers/pcmcia/pxa2xx_cm_x2xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_cm_x2xx.c b/drivers/pcmcia/pxa2xx_cm_x2xx.c index 4f09506ad8d4..6e7dcfd22ede 100644 --- a/drivers/pcmcia/pxa2xx_cm_x2xx.c +++ b/drivers/pcmcia/pxa2xx_cm_x2xx.c @@ -12,9 +12,8 @@ #include -#include #include -#include +#include int cmx255_pcmcia_init(void); int cmx270_pcmcia_init(void); From 0de9adf284ec20454ecf37ffd98e7e98ba7292d6 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Sat, 5 Nov 2011 09:04:47 -0400 Subject: [PATCH 1496/1596] MAINTAINERS: Update eCryptfs maintainer address Update my email address in MAINTAINERS. Signed-off-by: Tyler Hicks Signed-off-by: Linus Torvalds --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a6afe342f0fc..6388a96dc1c4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2387,7 +2387,7 @@ F: include/linux/netfilter_bridge/ebt_*.h F: net/bridge/netfilter/ebt*.c ECRYPT FILE SYSTEM -M: Tyler Hicks +M: Tyler Hicks M: Dustin Kirkland L: ecryptfs@vger.kernel.org W: https://launchpad.net/ecryptfs From c6ffe10015f4e6fba8a915318b319c43aed1836f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 3 Nov 2011 09:23:36 -0700 Subject: [PATCH 1497/1596] ceph: use new D_COMPLETE dentry flag We used to use a flag on the directory inode to track whether the dcache contents for a directory were a complete cached copy. Switch to a dentry flag CEPH_D_COMPLETE that is safely updated by ->d_prune(). Signed-off-by: Sage Weil --- fs/ceph/caps.c | 8 +++--- fs/ceph/dir.c | 59 +++++++++++++++++++++++++++++++++++++------- fs/ceph/inode.c | 8 +++--- fs/ceph/mds_client.c | 6 ++--- fs/ceph/super.h | 10 ++++++-- 5 files changed, 68 insertions(+), 23 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 15b21e35078a..0f327c6c9679 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -487,17 +487,15 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap, ci->i_rdcache_gen++; /* - * if we are newly issued FILE_SHARED, clear I_COMPLETE; we + * if we are newly issued FILE_SHARED, clear D_COMPLETE; we * don't know what happened to this directory while we didn't * have the cap. */ if ((issued & CEPH_CAP_FILE_SHARED) && (had & CEPH_CAP_FILE_SHARED) == 0) { ci->i_shared_gen++; - if (S_ISDIR(ci->vfs_inode.i_mode)) { - dout(" marking %p NOT complete\n", &ci->vfs_inode); - ci->i_ceph_flags &= ~CEPH_I_COMPLETE; - } + if (S_ISDIR(ci->vfs_inode.i_mode)) + ceph_dir_clear_complete(&ci->vfs_inode); } } diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 97fb155b3242..2abd0dfad7f8 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -108,7 +108,7 @@ static unsigned fpos_off(loff_t p) * falling back to a "normal" sync readdir if any dentries in the dir * are dropped. * - * I_COMPLETE tells indicates we have all dentries in the dir. It is + * D_COMPLETE tells indicates we have all dentries in the dir. It is * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by * the MDS if/when the directory is modified). */ @@ -199,8 +199,8 @@ static int __dcache_readdir(struct file *filp, filp->f_pos++; /* make sure a dentry wasn't dropped while we didn't have parent lock */ - if (!ceph_i_test(dir, CEPH_I_COMPLETE)) { - dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); + if (!ceph_dir_test_complete(dir)) { + dout(" lost D_COMPLETE on %p; falling back to mds\n", dir); err = -EAGAIN; goto out; } @@ -285,7 +285,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) if ((filp->f_pos == 2 || fi->dentry) && !ceph_test_mount_opt(fsc, NOASYNCREADDIR) && ceph_snap(inode) != CEPH_SNAPDIR && - (ci->i_ceph_flags & CEPH_I_COMPLETE) && + ceph_dir_test_complete(inode) && __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { spin_unlock(&inode->i_lock); err = __dcache_readdir(filp, dirent, filldir); @@ -351,7 +351,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) if (!req->r_did_prepopulate) { dout("readdir !did_prepopulate"); - fi->dir_release_count--; /* preclude I_COMPLETE */ + fi->dir_release_count--; /* preclude D_COMPLETE */ } /* note next offset and last dentry name */ @@ -430,8 +430,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) */ spin_lock(&inode->i_lock); if (ci->i_release_count == fi->dir_release_count) { - dout(" marking %p complete\n", inode); - /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */ + ceph_dir_set_complete(inode); ci->i_max_offset = filp->f_pos; } spin_unlock(&inode->i_lock); @@ -614,7 +613,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, fsc->mount_options->snapdir_name, dentry->d_name.len) && !is_root_ceph_dentry(dir, dentry) && - (ci->i_ceph_flags & CEPH_I_COMPLETE) && + ceph_dir_test_complete(dir) && (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { spin_unlock(&dir->i_lock); dout(" dir %p complete, -ENOENT\n", dir); @@ -934,7 +933,7 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, */ /* d_move screws up d_subdirs order */ - ceph_i_clear(new_dir, CEPH_I_COMPLETE); + ceph_dir_clear_complete(new_dir); d_move(old_dentry, new_dentry); @@ -1092,6 +1091,48 @@ static int ceph_snapdir_d_revalidate(struct dentry *dentry, return 1; } +/* + * Set/clear/test dir complete flag on the dir's dentry. + */ +static struct dentry * __d_find_any_alias(struct inode *inode) +{ + struct dentry *alias; + + if (list_empty(&inode->i_dentry)) + return NULL; + alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias); + return alias; +} + +void ceph_dir_set_complete(struct inode *inode) +{ + struct dentry *dentry = __d_find_any_alias(inode); + + if (dentry && ceph_dentry(dentry)) { + dout(" marking %p (%p) complete\n", inode, dentry); + set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); + } +} + +void ceph_dir_clear_complete(struct inode *inode) +{ + struct dentry *dentry = __d_find_any_alias(inode); + + if (dentry && ceph_dentry(dentry)) { + dout(" marking %p (%p) NOT complete\n", inode, dentry); + clear_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); + } +} + +bool ceph_dir_test_complete(struct inode *inode) +{ + struct dentry *dentry = __d_find_any_alias(inode); + + if (dentry && ceph_dentry(dentry)) + return test_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); + return false; +} + /* * When the VFS prunes a dentry from the cache, we need to clear the * complete flag on the parent directory. diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 1616a0d37cbd..e392bfce84a3 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -771,9 +771,9 @@ static int fill_inode(struct inode *inode, ceph_snap(inode) == CEPH_NOSNAP && (le32_to_cpu(info->cap.caps) & CEPH_CAP_FILE_SHARED) && (issued & CEPH_CAP_FILE_EXCL) == 0 && - (ci->i_ceph_flags & CEPH_I_COMPLETE) == 0) { + !ceph_dir_test_complete(inode)) { dout(" marking %p complete (empty)\n", inode); - /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */ + ceph_dir_set_complete(inode); ci->i_max_offset = 2; } @@ -856,7 +856,7 @@ static void ceph_set_dentry_offset(struct dentry *dn) di = ceph_dentry(dn); spin_lock(&inode->i_lock); - if ((ceph_inode(inode)->i_ceph_flags & CEPH_I_COMPLETE) == 0) { + if (!ceph_dir_test_complete(inode)) { spin_unlock(&inode->i_lock); return; } @@ -1056,7 +1056,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, * d_move() puts the renamed dentry at the end of * d_subdirs. We need to assign it an appropriate * directory offset so we can behave when holding - * I_COMPLETE. + * D_COMPLETE. */ ceph_set_dentry_offset(req->r_old_dentry); dout("dn %p gets new offset %lld\n", req->r_old_dentry, diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 1d72f15fe9f4..b4c3efa163c2 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2002,7 +2002,7 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc, } /* - * Invalidate dir I_COMPLETE, dentry lease state on an aborted MDS + * Invalidate dir D_COMPLETE, dentry lease state on an aborted MDS * namespace request. */ void ceph_invalidate_dir_request(struct ceph_mds_request *req) @@ -2010,9 +2010,9 @@ void ceph_invalidate_dir_request(struct ceph_mds_request *req) struct inode *inode = req->r_locked_dir; struct ceph_inode_info *ci = ceph_inode(inode); - dout("invalidate_dir_request %p (I_COMPLETE, lease(s))\n", inode); + dout("invalidate_dir_request %p (D_COMPLETE, lease(s))\n", inode); spin_lock(&inode->i_lock); - ci->i_ceph_flags &= ~CEPH_I_COMPLETE; + ceph_dir_clear_complete(inode); ci->i_release_count++; spin_unlock(&inode->i_lock); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 98e60693c9a1..01bf189e08a9 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -264,7 +264,7 @@ struct ceph_inode_info { struct timespec i_rctime; u64 i_rbytes, i_rfiles, i_rsubdirs; u64 i_files, i_subdirs; - u64 i_max_offset; /* largest readdir offset, set with I_COMPLETE */ + u64 i_max_offset; /* largest readdir offset, set with D_COMPLETE */ struct rb_root i_fragtree; struct mutex i_fragtree_mutex; @@ -429,7 +429,6 @@ static inline struct inode *ceph_find_inode(struct super_block *sb, /* * Ceph inode. */ -#define CEPH_I_COMPLETE 1 /* we have complete directory cached */ #define CEPH_I_NODELAY 4 /* do not delay cap release */ #define CEPH_I_FLUSH 8 /* do not delay flush of dirty metadata */ #define CEPH_I_NOFLUSH 16 /* do not flush dirty caps */ @@ -486,6 +485,13 @@ static inline loff_t ceph_make_fpos(unsigned frag, unsigned off) return ((loff_t)frag << 32) | (loff_t)off; } +/* + * set/clear directory D_COMPLETE flag + */ +void ceph_dir_set_complete(struct inode *inode); +void ceph_dir_clear_complete(struct inode *inode); +bool ceph_dir_test_complete(struct inode *inode); + /* * caps helpers */ From 7fd7d101ff50af55d6d69f4705facc00c324024e Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 23 Sep 2011 13:22:11 -0700 Subject: [PATCH 1498/1596] ceph/mds_client.c: quiet sparse noise Quiet the following sparse noise: warning: symbol 'get_nonsnap_parent' was not declared. Should it be static? warning: symbol 'done_closing_sessions' was not declared. Should it be static? Local functions don't need external visability. Make them static. Signed-off-by: H Hartley Sweeten Cc: Sage Weil Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b4c3efa163c2..264ab701154f 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -619,7 +619,7 @@ static void __unregister_request(struct ceph_mds_client *mdsc, * * Called under mdsc->mutex. */ -struct dentry *get_nonsnap_parent(struct dentry *dentry) +static struct dentry *get_nonsnap_parent(struct dentry *dentry) { /* * we don't need to worry about protecting the d_parent access @@ -3154,7 +3154,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc) /* * true if all sessions are closed, or we force unmount */ -bool done_closing_sessions(struct ceph_mds_client *mdsc) +static bool done_closing_sessions(struct ceph_mds_client *mdsc) { int i, n = 0; From 0c6d4b4e22a513f8563a2e00c5ab08e9f8796272 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 23 Sep 2011 11:53:30 -0700 Subject: [PATCH 1499/1596] ceph/super.c: quiet sparse noise Quiet the sparse noise: warning: symbol 'create_fs_client' was not declared. Should it be static? warning: symbol 'destroy_fs_client' was not declared. Should it be static? Signed-off-by: H Hartley Sweeten Cc: Sage Weil ceph-devel@vger.kernel.org Signed-off-by: Sage Weil --- fs/ceph/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 788f5ad8e66d..a90846fac759 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -426,7 +426,7 @@ static int extra_mon_dispatch(struct ceph_client *client, struct ceph_msg *msg) /* * create a new fs client */ -struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, +static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, struct ceph_options *opt) { struct ceph_fs_client *fsc; @@ -502,7 +502,7 @@ struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, return ERR_PTR(err); } -void destroy_fs_client(struct ceph_fs_client *fsc) +static void destroy_fs_client(struct ceph_fs_client *fsc) { dout("destroy_fs_client %p\n", fsc); From 8088041ee35604640760321621e3f058ea2c7061 Mon Sep 17 00:00:00 2001 From: Jonghwan Choi Date: Wed, 2 Nov 2011 20:13:30 +0900 Subject: [PATCH 1500/1596] ARM: SAMSUNG: Fix compile error due to kfree Fix following build error. arch/arm/plat-samsung/dev-backlight.c: In function 'samsung_bl_set': arch/arm/plat-samsung/dev-backlight.c:145: error: implicit declaration of function 'kfree' Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/dev-backlight.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c index 3cedd4c407af..2adbeaed4c04 100644 --- a/arch/arm/plat-samsung/dev-backlight.c +++ b/arch/arm/plat-samsung/dev-backlight.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include From d8633c1da161de7e0b880d919d305a97c01372f4 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 4 Nov 2011 10:39:34 +0900 Subject: [PATCH 1501/1596] ARM: SAMSUNG: Add clk enable/disable of pwm PWM timers use pclk("timers" clk) as parent clk. If this pclk is the disabled state when PWM driver is probed, then it causes wrong read and write operation about registers of PWM. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/pwm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/plat-samsung/pwm.c b/arch/arm/plat-samsung/pwm.c index f37457c52064..dc1185dcf80d 100644 --- a/arch/arm/plat-samsung/pwm.c +++ b/arch/arm/plat-samsung/pwm.c @@ -299,6 +299,9 @@ static int s3c_pwm_probe(struct platform_device *pdev) goto err_clk_tin; } + clk_enable(pwm->clk); + clk_enable(pwm->clk_div); + local_irq_save(flags); tcon = __raw_readl(S3C2410_TCON); @@ -326,6 +329,8 @@ static int s3c_pwm_probe(struct platform_device *pdev) return 0; err_clk_tdiv: + clk_disable(pwm->clk_div); + clk_disable(pwm->clk); clk_put(pwm->clk_div); err_clk_tin: @@ -340,6 +345,8 @@ static int __devexit s3c_pwm_remove(struct platform_device *pdev) { struct pwm_device *pwm = platform_get_drvdata(pdev); + clk_disable(pwm->clk_div); + clk_disable(pwm->clk); clk_put(pwm->clk_div); clk_put(pwm->clk); kfree(pwm); From e700e41d9abfbf9fee01e979a41b185695132c19 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 3 Nov 2011 11:13:12 +0900 Subject: [PATCH 1502/1596] ARM: EXYNOS4: convert MCT to percpu interrupt API MCT recently gained per cpu interrupts, and missed the fact that ARM has moved to a genirq based implementation. This patch converts the driver to the new API. Boot tested on Origen. Cc: Kukjin Kim Signed-off-by: Marc Zyngier Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos4/mct.c | 40 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c index f191608b28d6..97343df8f132 100644 --- a/arch/arm/mach-exynos4/mct.c +++ b/arch/arm/mach-exynos4/mct.c @@ -44,7 +44,7 @@ struct mct_clock_event_device { char name[10]; }; -struct mct_clock_event_device mct_tick[NR_CPUS]; +static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick); static void exynos4_mct_write(unsigned int value, void *addr) { @@ -302,7 +302,7 @@ static void exynos4_mct_tick_start(unsigned long cycles, static int exynos4_tick_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - struct mct_clock_event_device *mevt = &mct_tick[smp_processor_id()]; + struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); exynos4_mct_tick_start(cycles, mevt); @@ -312,7 +312,7 @@ static int exynos4_tick_set_next_event(unsigned long cycles, static inline void exynos4_tick_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { - struct mct_clock_event_device *mevt = &mct_tick[smp_processor_id()]; + struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); exynos4_mct_tick_stop(mevt); @@ -376,14 +376,16 @@ static struct irqaction mct_tick1_event_irq = { static void exynos4_mct_tick_init(struct clock_event_device *evt) { + struct mct_clock_event_device *mevt; unsigned int cpu = smp_processor_id(); - mct_tick[cpu].evt = evt; + mevt = this_cpu_ptr(&percpu_mct_tick); + mevt->evt = evt; - mct_tick[cpu].base = EXYNOS4_MCT_L_BASE(cpu); - sprintf(mct_tick[cpu].name, "mct_tick%d", cpu); + mevt->base = EXYNOS4_MCT_L_BASE(cpu); + sprintf(mevt->name, "mct_tick%d", cpu); - evt->name = mct_tick[cpu].name; + evt->name = mevt->name; evt->cpumask = cpumask_of(cpu); evt->set_next_event = exynos4_tick_set_next_event; evt->set_mode = exynos4_tick_set_mode; @@ -398,21 +400,21 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) clockevents_register_device(evt); - exynos4_mct_write(0x1, mct_tick[cpu].base + MCT_L_TCNTB_OFFSET); + exynos4_mct_write(0x1, mevt->base + MCT_L_TCNTB_OFFSET); if (mct_int_type == MCT_INT_SPI) { if (cpu == 0) { - mct_tick0_event_irq.dev_id = &mct_tick[cpu]; + mct_tick0_event_irq.dev_id = mevt; evt->irq = IRQ_MCT_L0; setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq); } else { - mct_tick1_event_irq.dev_id = &mct_tick[cpu]; + mct_tick1_event_irq.dev_id = mevt; evt->irq = IRQ_MCT_L1; setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq); irq_set_affinity(IRQ_MCT_L1, cpumask_of(1)); } } else { - gic_enable_ppi(IRQ_MCT_LOCALTIMER); + enable_percpu_irq(IRQ_MCT_LOCALTIMER, 0); } } @@ -427,9 +429,11 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) void local_timer_stop(struct clock_event_device *evt) { evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); - disable_irq(evt->irq); + if (mct_int_type == MCT_INT_SPI) + disable_irq(evt->irq); + else + disable_percpu_irq(IRQ_MCT_LOCALTIMER); } - #endif /* CONFIG_LOCAL_TIMERS */ static void __init exynos4_timer_resources(void) @@ -438,6 +442,16 @@ static void __init exynos4_timer_resources(void) mct_clk = clk_get(NULL, "xtal"); clk_rate = clk_get_rate(mct_clk); + + if (mct_int_type == MCT_INT_PPI) { + int err; + + err = request_percpu_irq(IRQ_MCT_LOCALTIMER, + exynos4_mct_tick_isr, "MCT", + &percpu_mct_tick); + WARN(err, "MCT: can't request IRQ %d (%d)\n", + IRQ_MCT_LOCALTIMER, err); + } } static void __init exynos4_timer_init(void) From 830145796a5c8f1ca3f87ea619063c1d99a57df5 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Sun, 6 Nov 2011 13:54:56 +0900 Subject: [PATCH 1503/1596] ARM: EXYNOS: Add ARCH_EXYNOS and reorganize arch/arm/mach-exynos The arch/arm/mach-exynos4 directory (CONFIG_ARCH_EXYNOS4) has made for plaforms based on EXYNOS4 SoCs. But since upcoming Samsung's SoCs such as EXYNOS5 (ARM Cortex A15) can reuse most codes in current mach-exynos4, one mach-exynos directory will be used for them. This patch changes to CONFIG_ARCH_EXYNOS (arch/arm/mach-exynos) but keeps original CONFIG_ARCH_EXYNOS4 in mach-exynos/Kconfig to avoid changing in driver side. Cc: Arnd Bergmann Cc: Russell King Signed-off-by: Kukjin Kim --- arch/arm/Kconfig | 8 +-- arch/arm/Makefile | 2 +- arch/arm/configs/exynos4_defconfig | 9 +-- .../arm/{mach-exynos4 => mach-exynos}/Kconfig | 42 ++++++++--- .../{mach-exynos4 => mach-exynos}/Makefile | 11 ++- .../Makefile.boot | 0 .../clock-exynos4210.c | 0 .../clock-exynos4212.c | 0 .../arm/{mach-exynos4 => mach-exynos}/clock.c | 0 arch/arm/{mach-exynos4 => mach-exynos}/cpu.c | 69 ++++++++++--------- .../{mach-exynos4 => mach-exynos}/cpuidle.c | 0 .../{mach-exynos4 => mach-exynos}/dev-ahci.c | 0 .../{mach-exynos4 => mach-exynos}/dev-audio.c | 0 .../{mach-exynos4 => mach-exynos}/dev-dwmci.c | 0 .../{mach-exynos4 => mach-exynos}/dev-pd.c | 0 .../dev-sysmmu.c | 0 arch/arm/{mach-exynos4 => mach-exynos}/dma.c | 0 .../{mach-exynos4 => mach-exynos}/headsmp.S | 0 .../{mach-exynos4 => mach-exynos}/hotplug.c | 0 .../include/mach/debug-macro.S | 0 .../include/mach/dma.h | 0 .../include/mach/dwmci.h | 0 .../include/mach/entry-macro.S | 0 .../include/mach/exynos4-clock.h | 0 .../include/mach/gpio.h | 0 .../include/mach/hardware.h | 0 .../include/mach/io.h | 0 .../include/mach/irqs.h | 0 .../include/mach/map.h | 32 +++++---- .../include/mach/memory.h | 0 .../include/mach/pm-core.h | 0 .../include/mach/pmu.h | 0 .../include/mach/regs-audss.h | 0 .../include/mach/regs-clock.h | 0 .../include/mach/regs-gpio.h | 0 .../include/mach/regs-irq.h | 0 .../include/mach/regs-mct.h | 0 .../include/mach/regs-mem.h | 0 .../include/mach/regs-pmu.h | 0 .../include/mach/regs-sysmmu.h | 0 .../include/mach/regs-usb-phy.h | 0 .../include/mach/sysmmu.h | 0 .../include/mach/system.h | 0 .../include/mach/timex.h | 0 .../include/mach/uncompress.h | 0 .../include/mach/vmalloc.h | 0 arch/arm/{mach-exynos4 => mach-exynos}/init.c | 0 .../irq-combiner.c | 0 .../{mach-exynos4 => mach-exynos}/irq-eint.c | 0 .../mach-armlex4210.c | 0 .../{mach-exynos4 => mach-exynos}/mach-nuri.c | 0 .../mach-origen.c | 0 .../mach-smdk4x12.c | 0 .../mach-smdkv310.c | 0 .../mach-universal_c210.c | 0 arch/arm/{mach-exynos4 => mach-exynos}/mct.c | 0 .../{mach-exynos4 => mach-exynos}/platsmp.c | 0 arch/arm/{mach-exynos4 => mach-exynos}/pm.c | 0 arch/arm/{mach-exynos4 => mach-exynos}/pmu.c | 0 .../setup-fimc.c | 0 .../setup-fimd0.c | 0 .../setup-i2c0.c | 0 .../setup-i2c1.c | 0 .../setup-i2c2.c | 0 .../setup-i2c3.c | 0 .../setup-i2c4.c | 0 .../setup-i2c5.c | 0 .../setup-i2c6.c | 0 .../setup-i2c7.c | 0 .../setup-keypad.c | 0 .../setup-sdhci-gpio.c | 0 .../setup-sdhci.c | 0 .../setup-usb-phy.c | 0 arch/arm/plat-s5p/Kconfig | 2 +- arch/arm/plat-s5p/cpu.c | 6 +- arch/arm/plat-samsung/include/plat/exynos4.h | 6 +- 76 files changed, 106 insertions(+), 81 deletions(-) rename arch/arm/{mach-exynos4 => mach-exynos}/Kconfig (92%) rename arch/arm/{mach-exynos4 => mach-exynos}/Makefile (90%) rename arch/arm/{mach-exynos4 => mach-exynos}/Makefile.boot (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/clock-exynos4210.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/clock-exynos4212.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/clock.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/cpu.c (91%) rename arch/arm/{mach-exynos4 => mach-exynos}/cpuidle.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/dev-ahci.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/dev-audio.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/dev-dwmci.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/dev-pd.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/dev-sysmmu.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/dma.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/headsmp.S (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/hotplug.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/debug-macro.S (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/dma.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/dwmci.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/entry-macro.S (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/exynos4-clock.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/gpio.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/hardware.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/io.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/irqs.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/map.h (93%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/memory.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/pm-core.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/pmu.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-audss.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-clock.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-gpio.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-irq.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-mct.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-mem.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-pmu.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-sysmmu.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/regs-usb-phy.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/sysmmu.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/system.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/timex.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/uncompress.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/include/mach/vmalloc.h (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/init.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/irq-combiner.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/irq-eint.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/mach-armlex4210.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/mach-nuri.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/mach-origen.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/mach-smdk4x12.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/mach-smdkv310.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/mach-universal_c210.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/mct.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/platsmp.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/pm.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/pmu.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-fimc.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-fimd0.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-i2c0.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-i2c1.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-i2c2.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-i2c3.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-i2c4.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-i2c5.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-i2c6.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-i2c7.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-keypad.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-sdhci-gpio.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-sdhci.c (100%) rename arch/arm/{mach-exynos4 => mach-exynos}/setup-usb-phy.c (100%) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2bda424c1b2b..44789eff983f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -837,8 +837,8 @@ config ARCH_S5PV210 help Samsung S5PV210/S5PC110 series based systems -config ARCH_EXYNOS4 - bool "Samsung EXYNOS4" +config ARCH_EXYNOS + bool "SAMSUNG EXYNOS" select CPU_V7 select ARCH_SPARSEMEM_ENABLE select ARCH_HAS_HOLES_MEMORYMODEL @@ -852,7 +852,7 @@ config ARCH_EXYNOS4 select HAVE_S3C2410_WATCHDOG if WATCHDOG select NEED_MACH_MEMORY_H help - Samsung EXYNOS4 series based systems + Support for SAMSUNG's EXYNOS SoCs (EXYNOS4/5) config ARCH_SHARK bool "Shark" @@ -1079,7 +1079,7 @@ source "arch/arm/mach-s5pc100/Kconfig" source "arch/arm/mach-s5pv210/Kconfig" -source "arch/arm/mach-exynos4/Kconfig" +source "arch/arm/mach-exynos/Kconfig" source "arch/arm/mach-shmobile/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index b7c2d377a6c2..dfcf3b033e10 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -180,7 +180,7 @@ machine-$(CONFIG_ARCH_S3C64XX) := s3c64xx machine-$(CONFIG_ARCH_S5P64X0) := s5p64x0 machine-$(CONFIG_ARCH_S5PC100) := s5pc100 machine-$(CONFIG_ARCH_S5PV210) := s5pv210 -machine-$(CONFIG_ARCH_EXYNOS4) := exynos4 +machine-$(CONFIG_ARCH_EXYNOS4) := exynos machine-$(CONFIG_ARCH_SA1100) := sa1100 machine-$(CONFIG_ARCH_SHARK) := shark machine-$(CONFIG_ARCH_SHMOBILE) := shmobile diff --git a/arch/arm/configs/exynos4_defconfig b/arch/arm/configs/exynos4_defconfig index cd40bb56e568..bffe68e190a3 100644 --- a/arch/arm/configs/exynos4_defconfig +++ b/arch/arm/configs/exynos4_defconfig @@ -4,19 +4,18 @@ CONFIG_KALLSYMS_ALL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set -CONFIG_ARCH_EXYNOS4=y +CONFIG_ARCH_EXYNOS=y CONFIG_S3C_LOWLEVEL_UART_PORT=1 CONFIG_MACH_SMDKC210=y -CONFIG_MACH_SMDKV310=y CONFIG_MACH_ARMLEX4210=y CONFIG_MACH_UNIVERSAL_C210=y CONFIG_MACH_NURI=y CONFIG_MACH_ORIGEN=y +CONFIG_MACH_SMDK4412=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc mem=256M" @@ -61,13 +60,9 @@ CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_RT_MUTEXES=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_DEBUG_USER=y -CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y CONFIG_EARLY_PRINTK=y -CONFIG_DEBUG_S3C_UART=1 CONFIG_CRC_CCITT=y diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos/Kconfig similarity index 92% rename from arch/arm/mach-exynos4/Kconfig rename to arch/arm/mach-exynos/Kconfig index 51cff04795d5..724ec0f3560d 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -1,4 +1,4 @@ -# arch/arm/mach-exynos4/Kconfig +# arch/arm/mach-exynos/Kconfig # # Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. # http://www.samsung.com/ @@ -7,10 +7,27 @@ # Configuration options for the EXYNOS4 -if ARCH_EXYNOS4 +if ARCH_EXYNOS + +menu "SAMSUNG EXYNOS SoCs Support" + +choice + prompt "EXYNOS System Type" + default ARCH_EXYNOS4 + +config ARCH_EXYNOS4 + bool "SAMSUNG EXYNOS4" + help + Samsung EXYNOS4 SoCs based systems + +endchoice + +comment "EXYNOS SoCs" config CPU_EXYNOS4210 - bool + bool "SAMSUNG EXYNOS4210" + default y + depends on ARCH_EXYNOS4 select SAMSUNG_DMADEV select ARM_CPU_SUSPEND if PM select S5P_PM if PM @@ -19,15 +36,18 @@ config CPU_EXYNOS4210 Enable EXYNOS4210 CPU support config SOC_EXYNOS4212 - bool - select ARM_CPU_SUSPEND if PM + bool "SAMSUNG EXYNOS4212" + default y + depends on ARCH_EXYNOS4 select S5P_PM if PM select S5P_SLEEP if PM help Enable EXYNOS4212 SoC support config SOC_EXYNOS4412 - bool + bool "SAMSUNG EXYNOS4412" + default y + depends on ARCH_EXYNOS4 help Enable EXYNOS4412 SoC support @@ -125,7 +145,7 @@ config EXYNOS4_SETUP_USB_PHY # machine support -menu "EXYNOS4 Machines" +if ARCH_EXYNOS4 comment "EXYNOS4210 Boards" @@ -305,12 +325,11 @@ config MACH_SMDK4412 select MACH_SMDK4212 help Machine support for Samsung SMDK4412 +endif -endmenu - -comment "Configuration for HSMMC bus width" +if ARCH_EXYNOS4 -menu "Use 8-bit bus width" +comment "Configuration for HSMMC 8-bit bus width" config EXYNOS4_SDHCI_CH0_8BIT bool "Channel 0 with 8-bit bus" @@ -323,6 +342,7 @@ config EXYNOS4_SDHCI_CH2_8BIT help Support HSMMC Channel 2 8-bit bus. If selected, Channel 3 is disabled. +endif endmenu diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos/Makefile similarity index 90% rename from arch/arm/mach-exynos4/Makefile rename to arch/arm/mach-exynos/Makefile index 2bb18f431db9..59069a35e40b 100644 --- a/arch/arm/mach-exynos4/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -1,4 +1,4 @@ -# arch/arm/mach-exynos4/Makefile +# arch/arm/mach-exynos/Makefile # # Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. # http://www.samsung.com/ @@ -12,8 +12,8 @@ obj- := # Core support for EXYNOS4 system -obj-$(CONFIG_ARCH_EXYNOS4) += cpu.o init.o clock.o irq-combiner.o -obj-$(CONFIG_ARCH_EXYNOS4) += setup-i2c0.o irq-eint.o dma.o pmu.o +obj-$(CONFIG_ARCH_EXYNOS4) += cpu.o init.o clock.o irq-combiner.o setup-i2c0.o +obj-$(CONFIG_ARCH_EXYNOS4) += irq-eint.o dma.o pmu.o obj-$(CONFIG_CPU_EXYNOS4210) += clock-exynos4210.o obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o obj-$(CONFIG_PM) += pm.o @@ -39,11 +39,11 @@ obj-$(CONFIG_MACH_SMDK4412) += mach-smdk4x12.o # device support -obj-y += dev-audio.o +obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o -obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o +obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o obj-$(CONFIG_EXYNOS4_SETUP_FIMD0) += setup-fimd0.o @@ -57,5 +57,4 @@ obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o - obj-$(CONFIG_EXYNOS4_SETUP_USB_PHY) += setup-usb-phy.o diff --git a/arch/arm/mach-exynos4/Makefile.boot b/arch/arm/mach-exynos/Makefile.boot similarity index 100% rename from arch/arm/mach-exynos4/Makefile.boot rename to arch/arm/mach-exynos/Makefile.boot diff --git a/arch/arm/mach-exynos4/clock-exynos4210.c b/arch/arm/mach-exynos/clock-exynos4210.c similarity index 100% rename from arch/arm/mach-exynos4/clock-exynos4210.c rename to arch/arm/mach-exynos/clock-exynos4210.c diff --git a/arch/arm/mach-exynos4/clock-exynos4212.c b/arch/arm/mach-exynos/clock-exynos4212.c similarity index 100% rename from arch/arm/mach-exynos4/clock-exynos4212.c rename to arch/arm/mach-exynos/clock-exynos4212.c diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos/clock.c similarity index 100% rename from arch/arm/mach-exynos4/clock.c rename to arch/arm/mach-exynos/clock.c diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos/cpu.c similarity index 91% rename from arch/arm/mach-exynos4/cpu.c rename to arch/arm/mach-exynos/cpu.c index 5b1765b37f75..90ec247f3b37 100644 --- a/arch/arm/mach-exynos4/cpu.c +++ b/arch/arm/mach-exynos/cpu.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-exynos4/cpu.c +/* linux/arch/arm/mach-exynos/cpu.c * * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com @@ -40,27 +40,46 @@ extern int combiner_init(unsigned int combiner_nr, void __iomem *base, extern void combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq); /* Initial IO mappings */ -static struct map_desc exynos4_iodesc[] __initdata = { +static struct map_desc exynos_iodesc[] __initdata = { { .virtual = (unsigned long)S5P_VA_SYSTIMER, - .pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER), + .pfn = __phys_to_pfn(EXYNOS_PA_SYSTIMER), .length = SZ_4K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S5P_VA_CMU, - .pfn = __phys_to_pfn(EXYNOS4_PA_CMU), - .length = SZ_128K, .type = MT_DEVICE, }, { .virtual = (unsigned long)S5P_VA_PMU, - .pfn = __phys_to_pfn(EXYNOS4_PA_PMU), + .pfn = __phys_to_pfn(EXYNOS_PA_PMU), .length = SZ_64K, .type = MT_DEVICE, }, { .virtual = (unsigned long)S5P_VA_COMBINER_BASE, - .pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER), + .pfn = __phys_to_pfn(EXYNOS_PA_COMBINER), .length = SZ_4K, .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S5P_VA_GIC_CPU, + .pfn = __phys_to_pfn(EXYNOS_PA_GIC_CPU), + .length = SZ_64K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S5P_VA_GIC_DIST, + .pfn = __phys_to_pfn(EXYNOS_PA_GIC_DIST), + .length = SZ_64K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C_VA_UART, + .pfn = __phys_to_pfn(S3C_PA_UART), + .length = SZ_512K, + .type = MT_DEVICE, + }, +}; + +static struct map_desc exynos4_iodesc[] __initdata = { + { + .virtual = (unsigned long)S5P_VA_CMU, + .pfn = __phys_to_pfn(EXYNOS4_PA_CMU), + .length = SZ_128K, + .type = MT_DEVICE, }, { .virtual = (unsigned long)S5P_VA_COREPERI_BASE, .pfn = __phys_to_pfn(EXYNOS4_PA_COREPERI), @@ -91,11 +110,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0), .length = SZ_4K, .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S3C_VA_UART, - .pfn = __phys_to_pfn(S3C_PA_UART), - .length = SZ_512K, - .type = MT_DEVICE, }, { .virtual = (unsigned long)S5P_VA_SROMC, .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC), @@ -106,16 +120,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY), .length = SZ_4K, .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S5P_VA_GIC_CPU, - .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_CPU), - .length = SZ_64K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S5P_VA_GIC_DIST, - .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_DIST), - .length = SZ_64K, - .type = MT_DEVICE, }, }; @@ -137,7 +141,7 @@ static struct map_desc exynos4_iodesc1[] __initdata = { }, }; -static void exynos4_idle(void) +static void exynos_idle(void) { if (!need_resched()) cpu_do_idle(); @@ -151,12 +155,13 @@ static void exynos4_sw_reset(void) } /* - * exynos4_map_io + * exynos_map_io * * register the standard cpu IO areas */ void __init exynos4_map_io(void) { + iotable_init(exynos_iodesc, ARRAY_SIZE(exynos_iodesc)); iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc)); if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_0) @@ -250,7 +255,6 @@ static int __init exynos4_core_init(void) { return sysdev_class_register(&exynos4_sysclass); } - core_initcall(exynos4_core_init); #ifdef CONFIG_CACHE_L2X0 @@ -279,15 +283,16 @@ static int __init exynos4_l2x0_cache_init(void) early_initcall(exynos4_l2x0_cache_init); #endif -int __init exynos4_init(void) +int __init exynos_init(void) { - printk(KERN_INFO "EXYNOS4: Initializing architecture\n"); + printk(KERN_INFO "EXYNOS: Initializing architecture\n"); /* set idle function */ - pm_idle = exynos4_idle; + pm_idle = exynos_idle; /* set sw_reset function */ - s5p_reset_hook = exynos4_sw_reset; + if (soc_is_exynos4210() || soc_is_exynos4212() || soc_is_exynos4412()) + s5p_reset_hook = exynos4_sw_reset; return sysdev_register(&exynos4_sysdev); } diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c similarity index 100% rename from arch/arm/mach-exynos4/cpuidle.c rename to arch/arm/mach-exynos/cpuidle.c diff --git a/arch/arm/mach-exynos4/dev-ahci.c b/arch/arm/mach-exynos/dev-ahci.c similarity index 100% rename from arch/arm/mach-exynos4/dev-ahci.c rename to arch/arm/mach-exynos/dev-ahci.c diff --git a/arch/arm/mach-exynos4/dev-audio.c b/arch/arm/mach-exynos/dev-audio.c similarity index 100% rename from arch/arm/mach-exynos4/dev-audio.c rename to arch/arm/mach-exynos/dev-audio.c diff --git a/arch/arm/mach-exynos4/dev-dwmci.c b/arch/arm/mach-exynos/dev-dwmci.c similarity index 100% rename from arch/arm/mach-exynos4/dev-dwmci.c rename to arch/arm/mach-exynos/dev-dwmci.c diff --git a/arch/arm/mach-exynos4/dev-pd.c b/arch/arm/mach-exynos/dev-pd.c similarity index 100% rename from arch/arm/mach-exynos4/dev-pd.c rename to arch/arm/mach-exynos/dev-pd.c diff --git a/arch/arm/mach-exynos4/dev-sysmmu.c b/arch/arm/mach-exynos/dev-sysmmu.c similarity index 100% rename from arch/arm/mach-exynos4/dev-sysmmu.c rename to arch/arm/mach-exynos/dev-sysmmu.c diff --git a/arch/arm/mach-exynos4/dma.c b/arch/arm/mach-exynos/dma.c similarity index 100% rename from arch/arm/mach-exynos4/dma.c rename to arch/arm/mach-exynos/dma.c diff --git a/arch/arm/mach-exynos4/headsmp.S b/arch/arm/mach-exynos/headsmp.S similarity index 100% rename from arch/arm/mach-exynos4/headsmp.S rename to arch/arm/mach-exynos/headsmp.S diff --git a/arch/arm/mach-exynos4/hotplug.c b/arch/arm/mach-exynos/hotplug.c similarity index 100% rename from arch/arm/mach-exynos4/hotplug.c rename to arch/arm/mach-exynos/hotplug.c diff --git a/arch/arm/mach-exynos4/include/mach/debug-macro.S b/arch/arm/mach-exynos/include/mach/debug-macro.S similarity index 100% rename from arch/arm/mach-exynos4/include/mach/debug-macro.S rename to arch/arm/mach-exynos/include/mach/debug-macro.S diff --git a/arch/arm/mach-exynos4/include/mach/dma.h b/arch/arm/mach-exynos/include/mach/dma.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/dma.h rename to arch/arm/mach-exynos/include/mach/dma.h diff --git a/arch/arm/mach-exynos4/include/mach/dwmci.h b/arch/arm/mach-exynos/include/mach/dwmci.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/dwmci.h rename to arch/arm/mach-exynos/include/mach/dwmci.h diff --git a/arch/arm/mach-exynos4/include/mach/entry-macro.S b/arch/arm/mach-exynos/include/mach/entry-macro.S similarity index 100% rename from arch/arm/mach-exynos4/include/mach/entry-macro.S rename to arch/arm/mach-exynos/include/mach/entry-macro.S diff --git a/arch/arm/mach-exynos4/include/mach/exynos4-clock.h b/arch/arm/mach-exynos/include/mach/exynos4-clock.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/exynos4-clock.h rename to arch/arm/mach-exynos/include/mach/exynos4-clock.h diff --git a/arch/arm/mach-exynos4/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/gpio.h rename to arch/arm/mach-exynos/include/mach/gpio.h diff --git a/arch/arm/mach-exynos4/include/mach/hardware.h b/arch/arm/mach-exynos/include/mach/hardware.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/hardware.h rename to arch/arm/mach-exynos/include/mach/hardware.h diff --git a/arch/arm/mach-exynos4/include/mach/io.h b/arch/arm/mach-exynos/include/mach/io.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/io.h rename to arch/arm/mach-exynos/include/mach/io.h diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/irqs.h rename to arch/arm/mach-exynos/include/mach/irqs.h diff --git a/arch/arm/mach-exynos4/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h similarity index 93% rename from arch/arm/mach-exynos4/include/mach/map.h rename to arch/arm/mach-exynos/include/mach/map.h index 918a979181af..058541d45af0 100644 --- a/arch/arm/mach-exynos4/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-exynos4/include/mach/map.h +/* linux/arch/arm/mach-exynos/include/mach/map.h * * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ @@ -145,39 +145,45 @@ #define S3C_PA_IIC5 EXYNOS4_PA_IIC(5) #define S3C_PA_IIC6 EXYNOS4_PA_IIC(6) #define S3C_PA_IIC7 EXYNOS4_PA_IIC(7) -#define SAMSUNG_PA_ADC EXYNOS4_PA_ADC -#define SAMSUNG_PA_ADC1 EXYNOS4_PA_ADC1 #define S3C_PA_RTC EXYNOS4_PA_RTC #define S3C_PA_WDT EXYNOS4_PA_WATCHDOG +#define S3C_PA_UART EXYNOS4_PA_UART #define S5P_PA_CHIPID EXYNOS4_PA_CHIPID +#define S5P_PA_EHCI EXYNOS4_PA_EHCI #define S5P_PA_FIMC0 EXYNOS4_PA_FIMC0 #define S5P_PA_FIMC1 EXYNOS4_PA_FIMC1 #define S5P_PA_FIMC2 EXYNOS4_PA_FIMC2 #define S5P_PA_FIMC3 EXYNOS4_PA_FIMC3 +#define S5P_PA_FIMD0 EXYNOS4_PA_FIMD0 +#define S5P_PA_HDMI EXYNOS4_PA_HDMI +#define S5P_PA_IIC_HDMIPHY EXYNOS4_PA_IIC_HDMIPHY +#define S5P_PA_MFC EXYNOS4_PA_MFC #define S5P_PA_MIPI_CSIS0 EXYNOS4_PA_MIPI_CSIS0 #define S5P_PA_MIPI_CSIS1 EXYNOS4_PA_MIPI_CSIS1 -#define S5P_PA_FIMD0 EXYNOS4_PA_FIMD0 +#define S5P_PA_MIXER EXYNOS4_PA_MIXER #define S5P_PA_ONENAND EXYNOS4_PA_ONENAND #define S5P_PA_ONENAND_DMA EXYNOS4_PA_ONENAND_DMA +#define S5P_PA_SDO EXYNOS4_PA_SDO #define S5P_PA_SDRAM EXYNOS4_PA_SDRAM #define S5P_PA_SROMC EXYNOS4_PA_SROMC -#define S5P_PA_MFC EXYNOS4_PA_MFC #define S5P_PA_SYSCON EXYNOS4_PA_SYSCON #define S5P_PA_TIMER EXYNOS4_PA_TIMER -#define S5P_PA_EHCI EXYNOS4_PA_EHCI - -#define S5P_PA_SDO EXYNOS4_PA_SDO #define S5P_PA_VP EXYNOS4_PA_VP -#define S5P_PA_MIXER EXYNOS4_PA_MIXER -#define S5P_PA_HDMI EXYNOS4_PA_HDMI -#define S5P_PA_IIC_HDMIPHY EXYNOS4_PA_IIC_HDMIPHY +#define SAMSUNG_PA_ADC EXYNOS4_PA_ADC +#define SAMSUNG_PA_ADC1 EXYNOS4_PA_ADC1 #define SAMSUNG_PA_KEYPAD EXYNOS4_PA_KEYPAD -/* UART */ +#define EXYNOS_PA_COMBINER EXYNOS4_PA_COMBINER +#define EXYNOS_PA_GIC_CPU EXYNOS4_PA_GIC_CPU +#define EXYNOS_PA_GIC_DIST EXYNOS4_PA_GIC_DIST +#define EXYNOS_PA_PMU EXYNOS4_PA_PMU +#define EXYNOS_PA_SYSTIMER EXYNOS4_PA_SYSTIMER -#define S3C_PA_UART EXYNOS4_PA_UART +/* Compatibility UART */ + +#define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) #define S5P_PA_UART(x) (S3C_PA_UART + ((x) * S3C_UART_OFFSET)) #define S5P_PA_UART0 S5P_PA_UART(0) diff --git a/arch/arm/mach-exynos4/include/mach/memory.h b/arch/arm/mach-exynos/include/mach/memory.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/memory.h rename to arch/arm/mach-exynos/include/mach/memory.h diff --git a/arch/arm/mach-exynos4/include/mach/pm-core.h b/arch/arm/mach-exynos/include/mach/pm-core.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/pm-core.h rename to arch/arm/mach-exynos/include/mach/pm-core.h diff --git a/arch/arm/mach-exynos4/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/pmu.h rename to arch/arm/mach-exynos/include/mach/pmu.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-audss.h b/arch/arm/mach-exynos/include/mach/regs-audss.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-audss.h rename to arch/arm/mach-exynos/include/mach/regs-audss.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-clock.h rename to arch/arm/mach-exynos/include/mach/regs-clock.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-gpio.h b/arch/arm/mach-exynos/include/mach/regs-gpio.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-gpio.h rename to arch/arm/mach-exynos/include/mach/regs-gpio.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-irq.h b/arch/arm/mach-exynos/include/mach/regs-irq.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-irq.h rename to arch/arm/mach-exynos/include/mach/regs-irq.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-mct.h b/arch/arm/mach-exynos/include/mach/regs-mct.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-mct.h rename to arch/arm/mach-exynos/include/mach/regs-mct.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-mem.h b/arch/arm/mach-exynos/include/mach/regs-mem.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-mem.h rename to arch/arm/mach-exynos/include/mach/regs-mem.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-pmu.h rename to arch/arm/mach-exynos/include/mach/regs-pmu.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h b/arch/arm/mach-exynos/include/mach/regs-sysmmu.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-sysmmu.h rename to arch/arm/mach-exynos/include/mach/regs-sysmmu.h diff --git a/arch/arm/mach-exynos4/include/mach/regs-usb-phy.h b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/regs-usb-phy.h rename to arch/arm/mach-exynos/include/mach/regs-usb-phy.h diff --git a/arch/arm/mach-exynos4/include/mach/sysmmu.h b/arch/arm/mach-exynos/include/mach/sysmmu.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/sysmmu.h rename to arch/arm/mach-exynos/include/mach/sysmmu.h diff --git a/arch/arm/mach-exynos4/include/mach/system.h b/arch/arm/mach-exynos/include/mach/system.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/system.h rename to arch/arm/mach-exynos/include/mach/system.h diff --git a/arch/arm/mach-exynos4/include/mach/timex.h b/arch/arm/mach-exynos/include/mach/timex.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/timex.h rename to arch/arm/mach-exynos/include/mach/timex.h diff --git a/arch/arm/mach-exynos4/include/mach/uncompress.h b/arch/arm/mach-exynos/include/mach/uncompress.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/uncompress.h rename to arch/arm/mach-exynos/include/mach/uncompress.h diff --git a/arch/arm/mach-exynos4/include/mach/vmalloc.h b/arch/arm/mach-exynos/include/mach/vmalloc.h similarity index 100% rename from arch/arm/mach-exynos4/include/mach/vmalloc.h rename to arch/arm/mach-exynos/include/mach/vmalloc.h diff --git a/arch/arm/mach-exynos4/init.c b/arch/arm/mach-exynos/init.c similarity index 100% rename from arch/arm/mach-exynos4/init.c rename to arch/arm/mach-exynos/init.c diff --git a/arch/arm/mach-exynos4/irq-combiner.c b/arch/arm/mach-exynos/irq-combiner.c similarity index 100% rename from arch/arm/mach-exynos4/irq-combiner.c rename to arch/arm/mach-exynos/irq-combiner.c diff --git a/arch/arm/mach-exynos4/irq-eint.c b/arch/arm/mach-exynos/irq-eint.c similarity index 100% rename from arch/arm/mach-exynos4/irq-eint.c rename to arch/arm/mach-exynos/irq-eint.c diff --git a/arch/arm/mach-exynos4/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c similarity index 100% rename from arch/arm/mach-exynos4/mach-armlex4210.c rename to arch/arm/mach-exynos/mach-armlex4210.c diff --git a/arch/arm/mach-exynos4/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c similarity index 100% rename from arch/arm/mach-exynos4/mach-nuri.c rename to arch/arm/mach-exynos/mach-nuri.c diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c similarity index 100% rename from arch/arm/mach-exynos4/mach-origen.c rename to arch/arm/mach-exynos/mach-origen.c diff --git a/arch/arm/mach-exynos4/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c similarity index 100% rename from arch/arm/mach-exynos4/mach-smdk4x12.c rename to arch/arm/mach-exynos/mach-smdk4x12.c diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c similarity index 100% rename from arch/arm/mach-exynos4/mach-smdkv310.c rename to arch/arm/mach-exynos/mach-smdkv310.c diff --git a/arch/arm/mach-exynos4/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c similarity index 100% rename from arch/arm/mach-exynos4/mach-universal_c210.c rename to arch/arm/mach-exynos/mach-universal_c210.c diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos/mct.c similarity index 100% rename from arch/arm/mach-exynos4/mct.c rename to arch/arm/mach-exynos/mct.c diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos/platsmp.c similarity index 100% rename from arch/arm/mach-exynos4/platsmp.c rename to arch/arm/mach-exynos/platsmp.c diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos/pm.c similarity index 100% rename from arch/arm/mach-exynos4/pm.c rename to arch/arm/mach-exynos/pm.c diff --git a/arch/arm/mach-exynos4/pmu.c b/arch/arm/mach-exynos/pmu.c similarity index 100% rename from arch/arm/mach-exynos4/pmu.c rename to arch/arm/mach-exynos/pmu.c diff --git a/arch/arm/mach-exynos4/setup-fimc.c b/arch/arm/mach-exynos/setup-fimc.c similarity index 100% rename from arch/arm/mach-exynos4/setup-fimc.c rename to arch/arm/mach-exynos/setup-fimc.c diff --git a/arch/arm/mach-exynos4/setup-fimd0.c b/arch/arm/mach-exynos/setup-fimd0.c similarity index 100% rename from arch/arm/mach-exynos4/setup-fimd0.c rename to arch/arm/mach-exynos/setup-fimd0.c diff --git a/arch/arm/mach-exynos4/setup-i2c0.c b/arch/arm/mach-exynos/setup-i2c0.c similarity index 100% rename from arch/arm/mach-exynos4/setup-i2c0.c rename to arch/arm/mach-exynos/setup-i2c0.c diff --git a/arch/arm/mach-exynos4/setup-i2c1.c b/arch/arm/mach-exynos/setup-i2c1.c similarity index 100% rename from arch/arm/mach-exynos4/setup-i2c1.c rename to arch/arm/mach-exynos/setup-i2c1.c diff --git a/arch/arm/mach-exynos4/setup-i2c2.c b/arch/arm/mach-exynos/setup-i2c2.c similarity index 100% rename from arch/arm/mach-exynos4/setup-i2c2.c rename to arch/arm/mach-exynos/setup-i2c2.c diff --git a/arch/arm/mach-exynos4/setup-i2c3.c b/arch/arm/mach-exynos/setup-i2c3.c similarity index 100% rename from arch/arm/mach-exynos4/setup-i2c3.c rename to arch/arm/mach-exynos/setup-i2c3.c diff --git a/arch/arm/mach-exynos4/setup-i2c4.c b/arch/arm/mach-exynos/setup-i2c4.c similarity index 100% rename from arch/arm/mach-exynos4/setup-i2c4.c rename to arch/arm/mach-exynos/setup-i2c4.c diff --git a/arch/arm/mach-exynos4/setup-i2c5.c b/arch/arm/mach-exynos/setup-i2c5.c similarity index 100% rename from arch/arm/mach-exynos4/setup-i2c5.c rename to arch/arm/mach-exynos/setup-i2c5.c diff --git a/arch/arm/mach-exynos4/setup-i2c6.c b/arch/arm/mach-exynos/setup-i2c6.c similarity index 100% rename from arch/arm/mach-exynos4/setup-i2c6.c rename to arch/arm/mach-exynos/setup-i2c6.c diff --git a/arch/arm/mach-exynos4/setup-i2c7.c b/arch/arm/mach-exynos/setup-i2c7.c similarity index 100% rename from arch/arm/mach-exynos4/setup-i2c7.c rename to arch/arm/mach-exynos/setup-i2c7.c diff --git a/arch/arm/mach-exynos4/setup-keypad.c b/arch/arm/mach-exynos/setup-keypad.c similarity index 100% rename from arch/arm/mach-exynos4/setup-keypad.c rename to arch/arm/mach-exynos/setup-keypad.c diff --git a/arch/arm/mach-exynos4/setup-sdhci-gpio.c b/arch/arm/mach-exynos/setup-sdhci-gpio.c similarity index 100% rename from arch/arm/mach-exynos4/setup-sdhci-gpio.c rename to arch/arm/mach-exynos/setup-sdhci-gpio.c diff --git a/arch/arm/mach-exynos4/setup-sdhci.c b/arch/arm/mach-exynos/setup-sdhci.c similarity index 100% rename from arch/arm/mach-exynos4/setup-sdhci.c rename to arch/arm/mach-exynos/setup-sdhci.c diff --git a/arch/arm/mach-exynos4/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c similarity index 100% rename from arch/arm/mach-exynos4/setup-usb-phy.c rename to arch/arm/mach-exynos/setup-usb-phy.c diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index ab16e5568c4c..9b9968fa8695 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -7,7 +7,7 @@ config PLAT_S5P bool - depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS4) + depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) default y select ARM_VIC if !ARCH_EXYNOS4 select ARM_GIC if ARCH_EXYNOS4 diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c index 7b0a28f73a68..a56959e83516 100644 --- a/arch/arm/plat-s5p/cpu.c +++ b/arch/arm/plat-s5p/cpu.c @@ -75,7 +75,7 @@ static struct cpu_table cpu_ids[] __initdata = { .map_io = exynos4_map_io, .init_clocks = exynos4_init_clocks, .init_uarts = exynos4_init_uarts, - .init = exynos4_init, + .init = exynos_init, .name = name_exynos4210, }, { .idcode = EXYNOS4212_CPU_ID, @@ -83,7 +83,7 @@ static struct cpu_table cpu_ids[] __initdata = { .map_io = exynos4_map_io, .init_clocks = exynos4_init_clocks, .init_uarts = exynos4_init_uarts, - .init = exynos4_init, + .init = exynos_init, .name = name_exynos4212, }, { .idcode = EXYNOS4412_CPU_ID, @@ -91,7 +91,7 @@ static struct cpu_table cpu_ids[] __initdata = { .map_io = exynos4_map_io, .init_clocks = exynos4_init_clocks, .init_uarts = exynos4_init_uarts, - .init = exynos4_init, + .init = exynos_init, .name = name_exynos4412, }, }; diff --git a/arch/arm/plat-samsung/include/plat/exynos4.h b/arch/arm/plat-samsung/include/plat/exynos4.h index 20d73bf77537..f546e88ebc94 100644 --- a/arch/arm/plat-samsung/include/plat/exynos4.h +++ b/arch/arm/plat-samsung/include/plat/exynos4.h @@ -18,8 +18,8 @@ extern void exynos4210_register_clocks(void); extern void exynos4212_register_clocks(void); extern void exynos4_setup_clocks(void); -#ifdef CONFIG_ARCH_EXYNOS4 -extern int exynos4_init(void); +#ifdef CONFIG_ARCH_EXYNOS +extern int exynos_init(void); extern void exynos4_init_irq(void); extern void exynos4_map_io(void); extern void exynos4_init_clocks(int xtal); @@ -31,5 +31,5 @@ extern struct sys_timer exynos4_timer; #define exynos4_init_clocks NULL #define exynos4_init_uarts NULL #define exynos4_map_io NULL -#define exynos4_init NULL +#define exynos_init NULL #endif From cd354ad613a393424f85333ceed6b15e07fb94ae Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 20 Oct 2011 15:45:37 -0400 Subject: [PATCH 1504/1596] Btrfs: don't wait as long for more batches during SSD log commit When we're doing log commits, we try to wait for more writers to come in and make the commit bigger. This helps improve performance on rotating disks, but on SSDs it adds latencies. Signed-off-by: Chris Mason --- fs/btrfs/tree-log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 786639fca067..310ab22cfe58 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2013,10 +2013,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, /* wait for previous tree log sync to complete */ if (atomic_read(&root->log_commit[(index1 + 1) % 2])) wait_log_commit(trans, root, root->log_transid - 1); - while (1) { unsigned long batch = root->log_batch; - if (root->log_multiple_pids) { + /* when we're on an ssd, just kick the log commit out */ + if (!btrfs_test_opt(root, SSD) && root->log_multiple_pids) { mutex_unlock(&root->log_mutex); schedule_timeout_uninterruptible(1); mutex_lock(&root->log_mutex); From 1eae31e918972bbeefc119d23c1d67674f49a301 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 14 Oct 2011 06:31:20 -0400 Subject: [PATCH 1505/1596] Btrfs: make sure btrfs_remove_free_space doesn't leak EAGAIN btrfs_remove_free_space needs to make sure to set ret back to a valid return value after setting it to EAGAIN, otherwise we return it to the callers. Signed-off-by: Chris Mason --- fs/btrfs/free-space-cache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index de205d59b74b..f49475dfa954 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -1868,6 +1868,7 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, ctl->total_bitmaps--; } kmem_cache_free(btrfs_free_space_cachep, info); + ret = 0; goto out_lock; } @@ -1875,7 +1876,8 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, unlink_free_space(ctl, info); info->offset += bytes; info->bytes -= bytes; - link_free_space(ctl, info); + ret = link_free_space(ctl, info); + WARN_ON(ret); goto out_lock; } From e688b7252f784c2479d559f9f70ca8354752c5e7 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Mon, 31 Oct 2011 20:52:39 -0400 Subject: [PATCH 1506/1596] Btrfs: fix extent pinning bugs in the tree log The tree log had two important bugs that could cause corruptions after a crash. Sometimes we were allowing tree log blocks to be reused after the tree log was committed but before the transaction commit was done. This allowed a future metadata write to overwrite the tree log data. It is fixed by adding a new variant of freeing reserved extents that always pins them. Credit goes to Stefan Behrens and Arne Jansen for many many hours spent tracking this bug down. During tree log replay, we do a pass through the tree log and pin all the extents we find. This makes sure the replay code won't go in and use any of those blocks for new allocations during replay. The problem is the free space cache isn't honoring these pinned extents. So the allocator can end up handing them out, leading to all kinds of problems during replay. The fix here is to force any free space cache to load while we pin the extents, and then to make sure we remove the pinned extents from the free space rbtree. Signed-off-by: Chris Mason Reported-by: Stefan Behrens --- fs/btrfs/ctree.h | 5 +++++ fs/btrfs/extent-tree.c | 51 +++++++++++++++++++++++++++++++++++++++--- fs/btrfs/tree-log.c | 11 ++++----- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 227620993bce..f63c9b3f6e08 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2156,6 +2156,9 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, u64 num_bytes, u64 *refs, u64 *flags); int btrfs_pin_extent(struct btrfs_root *root, u64 bytenr, u64 num, int reserved); +int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 bytenr, u64 num_bytes); int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 offset, u64 bytenr); @@ -2206,6 +2209,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, u64 root_objectid, u64 owner, u64 offset); int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); +int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root, + u64 start, u64 len); int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 28c4809851a5..cb7626646bba 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4344,6 +4344,34 @@ int btrfs_pin_extent(struct btrfs_root *root, return 0; } +/* + * this function must be called within transaction + */ +int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 bytenr, u64 num_bytes) +{ + struct btrfs_block_group_cache *cache; + + cache = btrfs_lookup_block_group(root->fs_info, bytenr); + BUG_ON(!cache); + + /* + * pull in the free space cache (if any) so that our pin + * removes the free space from the cache. We have load_only set + * to one because the slow code to read in the free extents does check + * the pinned extents. + */ + cache_block_group(cache, trans, root, 1); + + pin_down_extent(root, cache, bytenr, num_bytes, 0); + + /* remove us from the free space cache (if we're there at all) */ + btrfs_remove_free_space(cache, bytenr, num_bytes); + btrfs_put_block_group(cache); + return 0; +} + /** * btrfs_update_reserved_bytes - update the block_group and space info counters * @cache: The cache we are manipulating @@ -5487,7 +5515,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, return ret; } -int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len) +static int __btrfs_free_reserved_extent(struct btrfs_root *root, + u64 start, u64 len, int pin) { struct btrfs_block_group_cache *cache; int ret = 0; @@ -5502,8 +5531,12 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len) if (btrfs_test_opt(root, DISCARD)) ret = btrfs_discard_extent(root, start, len, NULL); - btrfs_add_free_space(cache, start, len); - btrfs_update_reserved_bytes(cache, len, RESERVE_FREE); + if (pin) + pin_down_extent(root, cache, start, len, 1); + else { + btrfs_add_free_space(cache, start, len); + btrfs_update_reserved_bytes(cache, len, RESERVE_FREE); + } btrfs_put_block_group(cache); trace_btrfs_reserved_extent_free(root, start, len); @@ -5511,6 +5544,18 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len) return ret; } +int btrfs_free_reserved_extent(struct btrfs_root *root, + u64 start, u64 len) +{ + return __btrfs_free_reserved_extent(root, start, len, 0); +} + +int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root, + u64 start, u64 len) +{ + return __btrfs_free_reserved_extent(root, start, len, 1); +} + static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 parent, u64 root_objectid, diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 310ab22cfe58..8ca1b6b83bd1 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -276,8 +276,9 @@ static int process_one_buffer(struct btrfs_root *log, struct walk_control *wc, u64 gen) { if (wc->pin) - btrfs_pin_extent(log->fs_info->extent_root, - eb->start, eb->len, 0); + btrfs_pin_extent_for_log_replay(wc->trans, + log->fs_info->extent_root, + eb->start, eb->len); if (btrfs_buffer_uptodate(eb, gen)) { if (wc->write) @@ -1760,7 +1761,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_reserved_extent(root, + ret = btrfs_free_and_pin_reserved_extent(root, bytenr, blocksize); BUG_ON(ret); } @@ -1828,7 +1829,7 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, btrfs_tree_unlock(next); WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_reserved_extent(root, + ret = btrfs_free_and_pin_reserved_extent(root, path->nodes[*level]->start, path->nodes[*level]->len); BUG_ON(ret); @@ -1897,7 +1898,7 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, WARN_ON(log->root_key.objectid != BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_reserved_extent(log, next->start, + ret = btrfs_free_and_pin_reserved_extent(log, next->start, next->len); BUG_ON(ret); } From 01d658f2ca3c85c1ffb20b306e30d16197000ce7 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 1 Nov 2011 10:08:06 -0400 Subject: [PATCH 1507/1596] Btrfs: make sure to flush queued bios if write_cache_pages waits write_cache_pages tries to build up a large bio to stuff down the pipe. But if it needs to wait for a page lock, it needs to make sure and send down any pending writes so we don't deadlock with anyone who has the page lock and is waiting for writeback of things inside the bio. Dave Sterba triggered this as a deadlock between the autodefrag code and the extent write_cache_pages Signed-off-by: Chris Mason --- fs/btrfs/disk-io.c | 13 ++++++++++--- fs/btrfs/disk-io.h | 2 -- fs/btrfs/extent_io.c | 14 ++++++++++---- fs/btrfs/extent_io.h | 3 ++- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 51372a521167..6f58911ece0d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2735,7 +2735,8 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) return ret; } -int btree_lock_page_hook(struct page *page) +static int btree_lock_page_hook(struct page *page, void *data, + void (*flush_fn)(void *)) { struct inode *inode = page->mapping->host; struct btrfs_root *root = BTRFS_I(inode)->root; @@ -2752,7 +2753,10 @@ int btree_lock_page_hook(struct page *page) if (!eb) goto out; - btrfs_tree_lock(eb); + if (!btrfs_try_tree_write_lock(eb)) { + flush_fn(data); + btrfs_tree_lock(eb); + } btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { @@ -2767,7 +2771,10 @@ int btree_lock_page_hook(struct page *page) btrfs_tree_unlock(eb); free_extent_buffer(eb); out: - lock_page(page); + if (!trylock_page(page)) { + flush_fn(data); + lock_page(page); + } return 0; } diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index bec3ea4bd67f..e678539c8519 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -83,8 +83,6 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); int btrfs_add_log_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root); -int btree_lock_page_hook(struct page *page); - #ifdef CONFIG_DEBUG_LOCK_ALLOC void btrfs_init_lockdep(void); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index f284d4e5f447..b40ba75f4483 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2613,10 +2613,16 @@ static int extent_write_cache_pages(struct extent_io_tree *tree, * swizzled back from swapper_space to tmpfs file * mapping */ - if (tree->ops && tree->ops->write_cache_pages_lock_hook) - tree->ops->write_cache_pages_lock_hook(page); - else - lock_page(page); + if (tree->ops && + tree->ops->write_cache_pages_lock_hook) { + tree->ops->write_cache_pages_lock_hook(page, + data, flush_fn); + } else { + if (!trylock_page(page)) { + flush_fn(data); + lock_page(page); + } + } if (unlikely(page->mapping != mapping)) { unlock_page(page); diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 325a346369da..cbd4824a7c94 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -86,7 +86,8 @@ struct extent_io_ops { struct extent_state *other); void (*split_extent_hook)(struct inode *inode, struct extent_state *orig, u64 split); - int (*write_cache_pages_lock_hook)(struct page *page); + int (*write_cache_pages_lock_hook)(struct page *page, void *data, + void (*flush_fn)(void *)); }; struct extent_io_tree { From 5a77d76c243be18d854aa1b14d697525f60e169a Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 1 Nov 2011 14:32:23 -0400 Subject: [PATCH 1508/1596] Btrfs: release metadata from global reserve if we have to fallback for unlink I fixed a problem where we weren't reserving space for an orphan item when we had to fallback to using the global reserve for an unlink, but I introduced another problem. I was migrating the bytes from the transaction reserve to the global reserve and then releasing from the global reserve in btrfs_end_transaction(). The problem with this is that a migrate will jack up the size for the destination, but leave the size alone for the source, with the idea that you can do a release normally on the source and it all washes out, and then you can do a release again on the destination and it works out right. My way was skipping the release on the trans_block_rsv which still had the jacked up size from our original reservation. So instead release manually from the global reserve if this transaction was using it, and then set the trans->block_rsv back to the trans_block_rsv so that btrfs_end_transaction cleans everything up properly. With this patch xfstest 83 doesn't emit warnings about leaking space. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/inode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 65474d95f26f..a8586e10953c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2904,7 +2904,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir, if (!err) err = btrfs_block_rsv_migrate(trans->block_rsv, &root->fs_info->global_block_rsv, - btrfs_calc_trans_metadata_size(root, 1)); + trans->bytes_reserved); if (err) { btrfs_end_transaction(trans, root); @@ -2920,6 +2920,9 @@ static void __unlink_end_trans(struct btrfs_trans_handle *trans, struct btrfs_root *root) { if (trans->block_rsv == &root->fs_info->global_block_rsv) { + btrfs_block_rsv_release(root, trans->block_rsv, + trans->bytes_reserved); + trans->block_rsv = &root->fs_info->trans_block_rsv; BUG_ON(!root->fs_info->enospc_unlink); root->fs_info->enospc_unlink = 0; } From c8174313a8102e874aaa321e2fc4c7c460a87151 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 2 Nov 2011 09:29:35 -0400 Subject: [PATCH 1509/1596] Btrfs: use the global reserve when truncating the free space cache inode We no longer use the orphan block rsv for holding the reservation for truncating the inode, so instead use the global block rsv and check to make sure it has enough space for us to truncate the space. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/free-space-cache.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index f49475dfa954..7a15fcfb3e1f 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -198,14 +198,24 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root, struct inode *inode) { struct btrfs_block_rsv *rsv; + u64 needed_bytes; loff_t oldsize; int ret = 0; rsv = trans->block_rsv; - trans->block_rsv = root->orphan_block_rsv; - ret = btrfs_block_rsv_check(root, root->orphan_block_rsv, 5); - if (ret) - return ret; + trans->block_rsv = &root->fs_info->global_block_rsv; + + /* 1 for slack space, 1 for updating the inode */ + needed_bytes = btrfs_calc_trunc_metadata_size(root, 1) + + btrfs_calc_trans_metadata_size(root, 1); + + spin_lock(&trans->block_rsv->lock); + if (trans->block_rsv->reserved < needed_bytes) { + spin_unlock(&trans->block_rsv->lock); + trans->block_rsv = rsv; + return -ENOSPC; + } + spin_unlock(&trans->block_rsv->lock); oldsize = i_size_read(inode); btrfs_i_size_write(inode, 0); @@ -218,13 +228,15 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root, ret = btrfs_truncate_inode_items(trans, root, inode, 0, BTRFS_EXTENT_DATA_KEY); - trans->block_rsv = rsv; if (ret) { + trans->block_rsv = rsv; WARN_ON(1); return ret; } ret = btrfs_update_inode(trans, root, inode); + trans->block_rsv = rsv; + return ret; } From 6c41761fc6efe1503103a1afe03a6635c0b5d4ec Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 13 Apr 2011 15:41:04 +0200 Subject: [PATCH 1510/1596] btrfs: separate superblock items out of fs_info fs_info has now ~9kb, more than fits into one page. This will cause mount failure when memory is too fragmented. Top space consumers are super block structures super_copy and super_for_commit, ~2.8kb each. Allocate them dynamically. fs_info will be ~3.5kb. (measured on x86_64) Add a wrapper for freeing fs_info and all of it's dynamically allocated members. Signed-off-by: David Sterba --- fs/btrfs/compression.c | 3 ++- fs/btrfs/ctree.h | 16 ++++++++++++++-- fs/btrfs/disk-io.c | 33 ++++++++++----------------------- fs/btrfs/extent-tree.c | 16 ++++++++-------- fs/btrfs/file-item.c | 17 ++++++----------- fs/btrfs/inode.c | 2 +- fs/btrfs/ioctl.c | 8 ++++---- fs/btrfs/scrub.c | 2 +- fs/btrfs/super.c | 19 +++++++++++++------ fs/btrfs/transaction.c | 10 +++++----- fs/btrfs/tree-log.c | 4 ++-- fs/btrfs/volumes.c | 24 ++++++++++++------------ 12 files changed, 78 insertions(+), 76 deletions(-) diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 8ec5d86f1734..14f1c5a0b2d2 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -85,7 +85,8 @@ struct compressed_bio { static inline int compressed_bio_size(struct btrfs_root *root, unsigned long disk_size) { - u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); + return sizeof(struct compressed_bio) + ((disk_size + root->sectorsize - 1) / root->sectorsize) * csum_size; diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f63c9b3f6e08..5181c53c1124 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -936,8 +936,8 @@ struct btrfs_fs_info { wait_queue_head_t transaction_blocked_wait; wait_queue_head_t async_submit_wait; - struct btrfs_super_block super_copy; - struct btrfs_super_block super_for_commit; + struct btrfs_super_block *super_copy; + struct btrfs_super_block *super_for_commit; struct block_device *__bdev; struct super_block *sb; struct inode *btree_inode; @@ -2387,6 +2387,18 @@ static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info) smp_mb(); return fs_info->closing; } +static inline void free_fs_info(struct btrfs_fs_info *fs_info) +{ + kfree(fs_info->delayed_root); + kfree(fs_info->extent_root); + kfree(fs_info->tree_root); + kfree(fs_info->chunk_root); + kfree(fs_info->dev_root); + kfree(fs_info->csum_root); + kfree(fs_info->super_copy); + kfree(fs_info->super_for_commit); + kfree(fs_info); +} /* root-item.c */ int btrfs_find_root_ref(struct btrfs_root *tree_root, diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 6f58911ece0d..761717c98278 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -256,8 +256,7 @@ void btrfs_csum_final(u32 crc, char *result) static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, int verify) { - u16 csum_size = - btrfs_super_csum_size(&root->fs_info->super_copy); + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); char *result = NULL; unsigned long len; unsigned long cur_len; @@ -1766,14 +1765,14 @@ struct btrfs_root *open_ctree(struct super_block *sb, goto fail_alloc; } - memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy)); - memcpy(&fs_info->super_for_commit, &fs_info->super_copy, - sizeof(fs_info->super_for_commit)); + memcpy(fs_info->super_copy, bh->b_data, sizeof(*fs_info->super_copy)); + memcpy(fs_info->super_for_commit, fs_info->super_copy, + sizeof(*fs_info->super_for_commit)); brelse(bh); - memcpy(fs_info->fsid, fs_info->super_copy.fsid, BTRFS_FSID_SIZE); + memcpy(fs_info->fsid, fs_info->super_copy->fsid, BTRFS_FSID_SIZE); - disk_super = &fs_info->super_copy; + disk_super = fs_info->super_copy; if (!btrfs_super_root(disk_super)) goto fail_alloc; @@ -2152,7 +2151,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, btrfs_stop_workers(&fs_info->delayed_workers); btrfs_stop_workers(&fs_info->caching_workers); fail_alloc: - kfree(fs_info->delayed_root); fail_iput: invalidate_inode_pages2(fs_info->btree_inode->i_mapping); iput(fs_info->btree_inode); @@ -2164,12 +2162,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, fail_srcu: cleanup_srcu_struct(&fs_info->subvol_srcu); fail: - kfree(extent_root); - kfree(tree_root); - kfree(fs_info); - kfree(chunk_root); - kfree(dev_root); - kfree(csum_root); + free_fs_info(fs_info); return ERR_PTR(err); } @@ -2338,10 +2331,10 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) int total_errors = 0; u64 flags; - max_errors = btrfs_super_num_devices(&root->fs_info->super_copy) - 1; + max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1; do_barriers = !btrfs_test_opt(root, NOBARRIER); - sb = &root->fs_info->super_for_commit; + sb = root->fs_info->super_for_commit; dev_item = &sb->dev_item; mutex_lock(&root->fs_info->fs_devices->device_list_mutex); @@ -2603,7 +2596,6 @@ int close_ctree(struct btrfs_root *root) del_fs_roots(fs_info); iput(fs_info->btree_inode); - kfree(fs_info->delayed_root); btrfs_stop_workers(&fs_info->generic_worker); btrfs_stop_workers(&fs_info->fixup_workers); @@ -2624,12 +2616,7 @@ int close_ctree(struct btrfs_root *root) bdi_destroy(&fs_info->bdi); cleanup_srcu_struct(&fs_info->subvol_srcu); - kfree(fs_info->extent_root); - kfree(fs_info->tree_root); - kfree(fs_info->chunk_root); - kfree(fs_info->dev_root); - kfree(fs_info->csum_root); - kfree(fs_info); + free_fs_info(fs_info); return 0; } diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index cb7626646bba..782eb3ea8edf 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3209,7 +3209,7 @@ static int should_alloc_chunk(struct btrfs_root *root, * about 1% of the FS size. */ if (force == CHUNK_ALLOC_LIMITED) { - thresh = btrfs_super_total_bytes(&root->fs_info->super_copy); + thresh = btrfs_super_total_bytes(root->fs_info->super_copy); thresh = max_t(u64, 64 * 1024 * 1024, div_factor_fine(thresh, 1)); @@ -3231,7 +3231,7 @@ static int should_alloc_chunk(struct btrfs_root *root, if (num_allocated + alloc_bytes < div_factor(num_bytes, 8)) return 0; - thresh = btrfs_super_total_bytes(&root->fs_info->super_copy); + thresh = btrfs_super_total_bytes(root->fs_info->super_copy); /* 256MB or 5% of the FS */ thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 5)); @@ -3843,7 +3843,7 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info) u64 num_bytes; u64 meta_used; u64 data_used; - int csum_size = btrfs_super_csum_size(&fs_info->super_copy); + int csum_size = btrfs_super_csum_size(fs_info->super_copy); sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA); spin_lock(&sinfo->lock); @@ -4222,12 +4222,12 @@ static int update_block_group(struct btrfs_trans_handle *trans, /* block accounting for super block */ spin_lock(&info->delalloc_lock); - old_val = btrfs_super_bytes_used(&info->super_copy); + old_val = btrfs_super_bytes_used(info->super_copy); if (alloc) old_val += num_bytes; else old_val -= num_bytes; - btrfs_set_super_bytes_used(&info->super_copy, old_val); + btrfs_set_super_bytes_used(info->super_copy, old_val); spin_unlock(&info->delalloc_lock); while (total) { @@ -7127,9 +7127,9 @@ int btrfs_read_block_groups(struct btrfs_root *root) return -ENOMEM; path->reada = 1; - cache_gen = btrfs_super_cache_generation(&root->fs_info->super_copy); + cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy); if (btrfs_test_opt(root, SPACE_CACHE) && - btrfs_super_generation(&root->fs_info->super_copy) != cache_gen) + btrfs_super_generation(root->fs_info->super_copy) != cache_gen) need_clear = 1; if (btrfs_test_opt(root, CLEAR_CACHE)) need_clear = 1; @@ -7458,7 +7458,7 @@ int btrfs_init_space_info(struct btrfs_fs_info *fs_info) int mixed = 0; int ret; - disk_super = &fs_info->super_copy; + disk_super = fs_info->super_copy; if (!btrfs_super_root(disk_super)) return 1; diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index a1cb7821becd..c7fb3a4247d3 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -91,8 +91,7 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_csum_item *item; struct extent_buffer *leaf; u64 csum_offset = 0; - u16 csum_size = - btrfs_super_csum_size(&root->fs_info->super_copy); + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); int csums_in_item; file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; @@ -162,8 +161,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, u64 item_last_offset = 0; u64 disk_bytenr; u32 diff; - u16 csum_size = - btrfs_super_csum_size(&root->fs_info->super_copy); + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); int ret; struct btrfs_path *path; struct btrfs_csum_item *item = NULL; @@ -290,7 +288,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, int ret; size_t size; u64 csum_end; - u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); path = btrfs_alloc_path(); if (!path) @@ -492,8 +490,7 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, u64 bytenr, u64 len) { struct extent_buffer *leaf; - u16 csum_size = - btrfs_super_csum_size(&root->fs_info->super_copy); + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); u64 csum_end; u64 end_byte = bytenr + len; u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; @@ -549,8 +546,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, u64 csum_end; struct extent_buffer *leaf; int ret; - u16 csum_size = - btrfs_super_csum_size(&root->fs_info->super_copy); + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); int blocksize_bits = root->fs_info->sb->s_blocksize_bits; root = root->fs_info->csum_root; @@ -676,8 +672,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, struct btrfs_sector_sum *sector_sum; u32 nritems; u32 ins_size; - u16 csum_size = - btrfs_super_csum_size(&root->fs_info->super_copy); + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); path = btrfs_alloc_path(); if (!path) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a8586e10953c..b6b612e14ed7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -824,7 +824,7 @@ static noinline int cow_file_range(struct inode *inode, } BUG_ON(disk_num_bytes > - btrfs_super_total_bytes(&root->fs_info->super_copy)); + btrfs_super_total_bytes(root->fs_info->super_copy)); alloc_hint = get_extent_allocation_hint(inode, start, num_bytes); btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 33aae13cc74b..8f6e14279409 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -282,7 +282,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) struct fstrim_range range; u64 minlen = ULLONG_MAX; u64 num_devices = 0; - u64 total_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); + u64 total_bytes = btrfs_super_total_bytes(root->fs_info->super_copy); int ret; if (!capable(CAP_SYS_ADMIN)) @@ -1164,7 +1164,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, mutex_unlock(&inode->i_mutex); } - disk_super = &root->fs_info->super_copy; + disk_super = root->fs_info->super_copy; features = btrfs_super_incompat_flags(disk_super); if (range->compress_type == BTRFS_COMPRESS_LZO) { features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; @@ -2613,7 +2613,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) return PTR_ERR(trans); } - dir_id = btrfs_super_root_dir(&root->fs_info->super_copy); + dir_id = btrfs_super_root_dir(root->fs_info->super_copy); di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path, dir_id, "default", 7, 1); if (IS_ERR_OR_NULL(di)) { @@ -2629,7 +2629,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_free_path(path); - disk_super = &root->fs_info->super_copy; + disk_super = root->fs_info->super_copy; features = btrfs_super_incompat_flags(disk_super); if (!(features & BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)) { features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index a8d03d5efb5d..69a600f07763 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -182,7 +182,7 @@ struct scrub_dev *scrub_setup_dev(struct btrfs_device *dev) sdev->curr = -1; atomic_set(&sdev->in_flight, 0); atomic_set(&sdev->cancel_req, 0); - sdev->csum_size = btrfs_super_csum_size(&fs_info->super_copy); + sdev->csum_size = btrfs_super_csum_size(fs_info->super_copy); INIT_LIST_HEAD(&sdev->csum_list); spin_lock_init(&sdev->list_lock); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 5429b1fa0bfc..f7e9de724ef2 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -216,7 +216,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) char *compress_type; bool compress_force = false; - cache_gen = btrfs_super_cache_generation(&root->fs_info->super_copy); + cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy); if (cache_gen) btrfs_set_opt(info->mount_opt, SPACE_CACHE); @@ -524,7 +524,7 @@ static struct dentry *get_default_root(struct super_block *sb, * will mount by default if we haven't been given a specific subvolume * to mount. */ - dir_id = btrfs_super_root_dir(&root->fs_info->super_copy); + dir_id = btrfs_super_root_dir(root->fs_info->super_copy); di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0); if (IS_ERR(di)) { btrfs_free_path(path); @@ -937,6 +937,13 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, fs_info->fs_devices = fs_devices; tree_root->fs_info = fs_info; + fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); + fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); + if (!fs_info->super_copy || !fs_info->super_for_commit) { + error = -ENOMEM; + goto error_close_devices; + } + bdev = fs_devices->latest_bdev; s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root); if (IS_ERR(s)) { @@ -951,7 +958,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, } btrfs_close_devices(fs_devices); - kfree(fs_info); + free_fs_info(fs_info); kfree(tree_root); } else { char b[BDEVNAME_SIZE]; @@ -979,7 +986,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, error_close_devices: btrfs_close_devices(fs_devices); - kfree(fs_info); + free_fs_info(fs_info); kfree(tree_root); return ERR_PTR(error); } @@ -1005,7 +1012,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) if (root->fs_info->fs_devices->rw_devices == 0) return -EACCES; - if (btrfs_super_log_root(&root->fs_info->super_copy) != 0) + if (btrfs_super_log_root(root->fs_info->super_copy) != 0) return -EINVAL; ret = btrfs_cleanup_fs_roots(root->fs_info); @@ -1171,7 +1178,7 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes) static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct btrfs_root *root = btrfs_sb(dentry->d_sb); - struct btrfs_super_block *disk_super = &root->fs_info->super_copy; + struct btrfs_super_block *disk_super = root->fs_info->super_copy; struct list_head *head = &root->fs_info->space_info; struct btrfs_space_info *found; u64 total_used = 0; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 29bef63e23ba..373c7ec1a026 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -991,7 +991,7 @@ static void update_super_roots(struct btrfs_root *root) struct btrfs_root_item *root_item; struct btrfs_super_block *super; - super = &root->fs_info->super_copy; + super = root->fs_info->super_copy; root_item = &root->fs_info->chunk_root->root_item; super->chunk_root = root_item->bytenr; @@ -1301,12 +1301,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, update_super_roots(root); if (!root->fs_info->log_root_recovering) { - btrfs_set_super_log_root(&root->fs_info->super_copy, 0); - btrfs_set_super_log_root_level(&root->fs_info->super_copy, 0); + btrfs_set_super_log_root(root->fs_info->super_copy, 0); + btrfs_set_super_log_root_level(root->fs_info->super_copy, 0); } - memcpy(&root->fs_info->super_for_commit, &root->fs_info->super_copy, - sizeof(root->fs_info->super_copy)); + memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy, + sizeof(*root->fs_info->super_copy)); trans->transaction->blocked = 0; spin_lock(&root->fs_info->trans_lock); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 8ca1b6b83bd1..f4d81c06d48f 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2118,9 +2118,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, BUG_ON(ret); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); - btrfs_set_super_log_root(&root->fs_info->super_for_commit, + btrfs_set_super_log_root(root->fs_info->super_for_commit, log_root_tree->node->start); - btrfs_set_super_log_root_level(&root->fs_info->super_for_commit, + btrfs_set_super_log_root_level(root->fs_info->super_for_commit, btrfs_header_level(log_root_tree->node)); log_root_tree->log_batch = 0; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index c6938b45e0fd..c3b45564048e 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1395,8 +1395,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) call_rcu(&device->rcu, free_device); mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - num_devices = btrfs_super_num_devices(&root->fs_info->super_copy) - 1; - btrfs_set_super_num_devices(&root->fs_info->super_copy, num_devices); + num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1; + btrfs_set_super_num_devices(root->fs_info->super_copy, num_devices); if (cur_devices->open_devices == 0) { struct btrfs_fs_devices *fs_devices; @@ -1458,7 +1458,7 @@ static int btrfs_prepare_sprout(struct btrfs_trans_handle *trans, struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; struct btrfs_fs_devices *old_devices; struct btrfs_fs_devices *seed_devices; - struct btrfs_super_block *disk_super = &root->fs_info->super_copy; + struct btrfs_super_block *disk_super = root->fs_info->super_copy; struct btrfs_device *device; u64 super_flags; @@ -1706,12 +1706,12 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) if (!blk_queue_nonrot(bdev_get_queue(bdev))) root->fs_info->fs_devices->rotating = 1; - total_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); - btrfs_set_super_total_bytes(&root->fs_info->super_copy, + total_bytes = btrfs_super_total_bytes(root->fs_info->super_copy); + btrfs_set_super_total_bytes(root->fs_info->super_copy, total_bytes + device->total_bytes); - total_bytes = btrfs_super_num_devices(&root->fs_info->super_copy); - btrfs_set_super_num_devices(&root->fs_info->super_copy, + total_bytes = btrfs_super_num_devices(root->fs_info->super_copy); + btrfs_set_super_num_devices(root->fs_info->super_copy, total_bytes + 1); mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); @@ -1802,7 +1802,7 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 new_size) { struct btrfs_super_block *super_copy = - &device->dev_root->fs_info->super_copy; + device->dev_root->fs_info->super_copy; u64 old_total = btrfs_super_total_bytes(super_copy); u64 diff = new_size - device->total_bytes; @@ -1861,7 +1861,7 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans, static int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64 chunk_offset) { - struct btrfs_super_block *super_copy = &root->fs_info->super_copy; + struct btrfs_super_block *super_copy = root->fs_info->super_copy; struct btrfs_disk_key *disk_key; struct btrfs_chunk *chunk; u8 *ptr; @@ -2187,7 +2187,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) bool retried = false; struct extent_buffer *l; struct btrfs_key key; - struct btrfs_super_block *super_copy = &root->fs_info->super_copy; + struct btrfs_super_block *super_copy = root->fs_info->super_copy; u64 old_total = btrfs_super_total_bytes(super_copy); u64 old_size = device->total_bytes; u64 diff = device->total_bytes - new_size; @@ -2311,7 +2311,7 @@ static int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, struct btrfs_key *key, struct btrfs_chunk *chunk, int item_size) { - struct btrfs_super_block *super_copy = &root->fs_info->super_copy; + struct btrfs_super_block *super_copy = root->fs_info->super_copy; struct btrfs_disk_key disk_key; u32 array_size; u8 *ptr; @@ -3653,7 +3653,7 @@ static int read_one_dev(struct btrfs_root *root, int btrfs_read_sys_array(struct btrfs_root *root) { - struct btrfs_super_block *super_copy = &root->fs_info->super_copy; + struct btrfs_super_block *super_copy = root->fs_info->super_copy; struct extent_buffer *sb; struct btrfs_disk_key *disk_key; struct btrfs_chunk *chunk; From af31f5e5b84b5bf2bcec464153a5130b170b2770 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 3 Nov 2011 15:17:42 -0400 Subject: [PATCH 1511/1596] Btrfs: add a log of past tree roots This takes some of the free space in the btrfs super block to record information about most of the roots in the last four commits. It also adds a -o recovery to use the root history log when we're not able to read the tree of tree roots, the extent tree root, the device tree root or the csum root. Signed-off-by: Chris Mason --- fs/btrfs/ctree.h | 95 +++++++++++++++ fs/btrfs/disk-io.c | 291 +++++++++++++++++++++++++++++++++++++++++---- fs/btrfs/super.c | 7 +- 3 files changed, 369 insertions(+), 24 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5181c53c1124..78f43d1102a0 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -360,6 +360,47 @@ struct btrfs_header { #define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 #define BTRFS_LABEL_SIZE 256 +/* + * just in case we somehow lose the roots and are not able to mount, + * we store an array of the roots from previous transactions + * in the super. + */ +#define BTRFS_NUM_BACKUP_ROOTS 4 +struct btrfs_root_backup { + __le64 tree_root; + __le64 tree_root_gen; + + __le64 chunk_root; + __le64 chunk_root_gen; + + __le64 extent_root; + __le64 extent_root_gen; + + __le64 fs_root; + __le64 fs_root_gen; + + __le64 dev_root; + __le64 dev_root_gen; + + __le64 csum_root; + __le64 csum_root_gen; + + __le64 total_bytes; + __le64 bytes_used; + __le64 num_devices; + /* future */ + __le64 unsed_64[4]; + + u8 tree_root_level; + u8 chunk_root_level; + u8 extent_root_level; + u8 fs_root_level; + u8 dev_root_level; + u8 csum_root_level; + /* future and to align */ + u8 unused_8[10]; +} __attribute__ ((__packed__)); + /* * the super block basically lists the main trees of the FS * it currently lacks any block count etc etc @@ -406,6 +447,7 @@ struct btrfs_super_block { /* future expansion */ __le64 reserved[31]; u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; + struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; } __attribute__ ((__packed__)); /* @@ -1113,6 +1155,9 @@ struct btrfs_fs_info { u64 fs_state; struct btrfs_delayed_root *delayed_root; + + /* next backup root to be overwritten */ + int backup_root_index; }; /* @@ -1357,6 +1402,7 @@ struct btrfs_ioctl_defrag_range_args { #define BTRFS_MOUNT_ENOSPC_DEBUG (1 << 15) #define BTRFS_MOUNT_AUTO_DEFRAG (1 << 16) #define BTRFS_MOUNT_INODE_MAP_CACHE (1 << 17) +#define BTRFS_MOUNT_RECOVERY (1 << 18) #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) @@ -1972,6 +2018,55 @@ static inline bool btrfs_root_readonly(struct btrfs_root *root) return root->root_item.flags & BTRFS_ROOT_SUBVOL_RDONLY; } +/* struct btrfs_root_backup */ +BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, + tree_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup, + tree_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup, + tree_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup, + chunk_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup, + chunk_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup, + chunk_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup, + extent_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup, + extent_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup, + extent_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup, + fs_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup, + fs_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup, + fs_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup, + dev_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup, + dev_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup, + dev_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup, + csum_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup, + csum_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup, + csum_root_level, 8); +BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup, + total_bytes, 64); +BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup, + bytes_used, 64); +BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup, + num_devices, 64); + /* struct btrfs_super_block */ BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 761717c98278..a61f8a6cf219 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1134,10 +1134,12 @@ static int find_and_setup_root(struct btrfs_root *tree_root, generation = btrfs_root_generation(&root->root_item); blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); + root->commit_root = NULL; root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), blocksize, generation); if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { free_extent_buffer(root->node); + root->node = NULL; return -EIO; } root->commit_root = btrfs_root_node(root); @@ -1576,6 +1578,228 @@ static int transaction_kthread(void *arg) return 0; } +/* + * this will find the highest generation in the array of + * root backups. The index of the highest array is returned, + * or -1 if we can't find anything. + * + * We check to make sure the array is valid by comparing the + * generation of the latest root in the array with the generation + * in the super block. If they don't match we pitch it. + */ +static int find_newest_super_backup(struct btrfs_fs_info *info, u64 newest_gen) +{ + u64 cur; + int newest_index = -1; + struct btrfs_root_backup *root_backup; + int i; + + for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) { + root_backup = info->super_copy->super_roots + i; + cur = btrfs_backup_tree_root_gen(root_backup); + if (cur == newest_gen) + newest_index = i; + } + + /* check to see if we actually wrapped around */ + if (newest_index == BTRFS_NUM_BACKUP_ROOTS - 1) { + root_backup = info->super_copy->super_roots; + cur = btrfs_backup_tree_root_gen(root_backup); + if (cur == newest_gen) + newest_index = 0; + } + return newest_index; +} + + +/* + * find the oldest backup so we know where to store new entries + * in the backup array. This will set the backup_root_index + * field in the fs_info struct + */ +static void find_oldest_super_backup(struct btrfs_fs_info *info, + u64 newest_gen) +{ + int newest_index = -1; + + newest_index = find_newest_super_backup(info, newest_gen); + /* if there was garbage in there, just move along */ + if (newest_index == -1) { + info->backup_root_index = 0; + } else { + info->backup_root_index = (newest_index + 1) % BTRFS_NUM_BACKUP_ROOTS; + } +} + +/* + * copy all the root pointers into the super backup array. + * this will bump the backup pointer by one when it is + * done + */ +static void backup_super_roots(struct btrfs_fs_info *info) +{ + int next_backup; + struct btrfs_root_backup *root_backup; + int last_backup; + + next_backup = info->backup_root_index; + last_backup = (next_backup + BTRFS_NUM_BACKUP_ROOTS - 1) % + BTRFS_NUM_BACKUP_ROOTS; + + /* + * just overwrite the last backup if we're at the same generation + * this happens only at umount + */ + root_backup = info->super_for_commit->super_roots + last_backup; + if (btrfs_backup_tree_root_gen(root_backup) == + btrfs_header_generation(info->tree_root->node)) + next_backup = last_backup; + + root_backup = info->super_for_commit->super_roots + next_backup; + + /* + * make sure all of our padding and empty slots get zero filled + * regardless of which ones we use today + */ + memset(root_backup, 0, sizeof(*root_backup)); + + info->backup_root_index = (next_backup + 1) % BTRFS_NUM_BACKUP_ROOTS; + + btrfs_set_backup_tree_root(root_backup, info->tree_root->node->start); + btrfs_set_backup_tree_root_gen(root_backup, + btrfs_header_generation(info->tree_root->node)); + + btrfs_set_backup_tree_root_level(root_backup, + btrfs_header_level(info->tree_root->node)); + + btrfs_set_backup_chunk_root(root_backup, info->chunk_root->node->start); + btrfs_set_backup_chunk_root_gen(root_backup, + btrfs_header_generation(info->chunk_root->node)); + btrfs_set_backup_chunk_root_level(root_backup, + btrfs_header_level(info->chunk_root->node)); + + btrfs_set_backup_extent_root(root_backup, info->extent_root->node->start); + btrfs_set_backup_extent_root_gen(root_backup, + btrfs_header_generation(info->extent_root->node)); + btrfs_set_backup_extent_root_level(root_backup, + btrfs_header_level(info->extent_root->node)); + + btrfs_set_backup_fs_root(root_backup, info->fs_root->node->start); + btrfs_set_backup_fs_root_gen(root_backup, + btrfs_header_generation(info->fs_root->node)); + btrfs_set_backup_fs_root_level(root_backup, + btrfs_header_level(info->fs_root->node)); + + btrfs_set_backup_dev_root(root_backup, info->dev_root->node->start); + btrfs_set_backup_dev_root_gen(root_backup, + btrfs_header_generation(info->dev_root->node)); + btrfs_set_backup_dev_root_level(root_backup, + btrfs_header_level(info->dev_root->node)); + + btrfs_set_backup_csum_root(root_backup, info->csum_root->node->start); + btrfs_set_backup_csum_root_gen(root_backup, + btrfs_header_generation(info->csum_root->node)); + btrfs_set_backup_csum_root_level(root_backup, + btrfs_header_level(info->csum_root->node)); + + btrfs_set_backup_total_bytes(root_backup, + btrfs_super_total_bytes(info->super_copy)); + btrfs_set_backup_bytes_used(root_backup, + btrfs_super_bytes_used(info->super_copy)); + btrfs_set_backup_num_devices(root_backup, + btrfs_super_num_devices(info->super_copy)); + + /* + * if we don't copy this out to the super_copy, it won't get remembered + * for the next commit + */ + memcpy(&info->super_copy->super_roots, + &info->super_for_commit->super_roots, + sizeof(*root_backup) * BTRFS_NUM_BACKUP_ROOTS); +} + +/* + * this copies info out of the root backup array and back into + * the in-memory super block. It is meant to help iterate through + * the array, so you send it the number of backups you've already + * tried and the last backup index you used. + * + * this returns -1 when it has tried all the backups + */ +static noinline int next_root_backup(struct btrfs_fs_info *info, + struct btrfs_super_block *super, + int *num_backups_tried, int *backup_index) +{ + struct btrfs_root_backup *root_backup; + int newest = *backup_index; + + if (*num_backups_tried == 0) { + u64 gen = btrfs_super_generation(super); + + newest = find_newest_super_backup(info, gen); + if (newest == -1) + return -1; + + *backup_index = newest; + *num_backups_tried = 1; + } else if (*num_backups_tried == BTRFS_NUM_BACKUP_ROOTS) { + /* we've tried all the backups, all done */ + return -1; + } else { + /* jump to the next oldest backup */ + newest = (*backup_index + BTRFS_NUM_BACKUP_ROOTS - 1) % + BTRFS_NUM_BACKUP_ROOTS; + *backup_index = newest; + *num_backups_tried += 1; + } + root_backup = super->super_roots + newest; + + btrfs_set_super_generation(super, + btrfs_backup_tree_root_gen(root_backup)); + btrfs_set_super_root(super, btrfs_backup_tree_root(root_backup)); + btrfs_set_super_root_level(super, + btrfs_backup_tree_root_level(root_backup)); + btrfs_set_super_bytes_used(super, btrfs_backup_bytes_used(root_backup)); + + /* + * fixme: the total bytes and num_devices need to match or we should + * need a fsck + */ + btrfs_set_super_total_bytes(super, btrfs_backup_total_bytes(root_backup)); + btrfs_set_super_num_devices(super, btrfs_backup_num_devices(root_backup)); + return 0; +} + +/* helper to cleanup tree roots */ +static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root) +{ + free_extent_buffer(info->tree_root->node); + free_extent_buffer(info->tree_root->commit_root); + free_extent_buffer(info->dev_root->node); + free_extent_buffer(info->dev_root->commit_root); + free_extent_buffer(info->extent_root->node); + free_extent_buffer(info->extent_root->commit_root); + free_extent_buffer(info->csum_root->node); + free_extent_buffer(info->csum_root->commit_root); + + info->tree_root->node = NULL; + info->tree_root->commit_root = NULL; + info->dev_root->node = NULL; + info->dev_root->commit_root = NULL; + info->extent_root->node = NULL; + info->extent_root->commit_root = NULL; + info->csum_root->node = NULL; + info->csum_root->commit_root = NULL; + + if (chunk_root) { + free_extent_buffer(info->chunk_root->node); + free_extent_buffer(info->chunk_root->commit_root); + info->chunk_root->node = NULL; + info->chunk_root->commit_root = NULL; + } +} + + struct btrfs_root *open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices, char *options) @@ -1603,6 +1827,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, int ret; int err = -EINVAL; + int num_backups_tried = 0; + int backup_index = 0; struct btrfs_super_block *disk_super; @@ -1781,6 +2007,13 @@ struct btrfs_root *open_ctree(struct super_block *sb, btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); + /* + * run through our array of backup supers and setup + * our ring pointer to the oldest one + */ + generation = btrfs_super_generation(disk_super); + find_oldest_super_backup(fs_info, generation); + /* * In the long term, we'll store the compression type in the super * block, and it'll be used for per file compression control. @@ -1938,7 +2171,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) { printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n", sb->s_id); - goto fail_chunk_root; + goto fail_tree_roots; } btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); chunk_root->commit_root = btrfs_root_node(chunk_root); @@ -1953,11 +2186,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, if (ret) { printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n", sb->s_id); - goto fail_chunk_root; + goto fail_tree_roots; } btrfs_close_extra_devices(fs_devices); +retry_root_backup: blocksize = btrfs_level_size(tree_root, btrfs_super_root_level(disk_super)); generation = btrfs_super_generation(disk_super); @@ -1965,32 +2199,33 @@ struct btrfs_root *open_ctree(struct super_block *sb, tree_root->node = read_tree_block(tree_root, btrfs_super_root(disk_super), blocksize, generation); - if (!tree_root->node) - goto fail_chunk_root; - if (!test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) { + if (!tree_root->node || + !test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) { printk(KERN_WARNING "btrfs: failed to read tree root on %s\n", sb->s_id); - goto fail_tree_root; + + goto recovery_tree_root; } + btrfs_set_root_node(&tree_root->root_item, tree_root->node); tree_root->commit_root = btrfs_root_node(tree_root); ret = find_and_setup_root(tree_root, fs_info, BTRFS_EXTENT_TREE_OBJECTID, extent_root); if (ret) - goto fail_tree_root; + goto recovery_tree_root; extent_root->track_dirty = 1; ret = find_and_setup_root(tree_root, fs_info, BTRFS_DEV_TREE_OBJECTID, dev_root); if (ret) - goto fail_extent_root; + goto recovery_tree_root; dev_root->track_dirty = 1; ret = find_and_setup_root(tree_root, fs_info, BTRFS_CSUM_TREE_OBJECTID, csum_root); if (ret) - goto fail_dev_root; + goto recovery_tree_root; csum_root->track_dirty = 1; @@ -2123,20 +2358,10 @@ struct btrfs_root *open_ctree(struct super_block *sb, fail_block_groups: btrfs_free_block_groups(fs_info); - free_extent_buffer(csum_root->node); - free_extent_buffer(csum_root->commit_root); -fail_dev_root: - free_extent_buffer(dev_root->node); - free_extent_buffer(dev_root->commit_root); -fail_extent_root: - free_extent_buffer(extent_root->node); - free_extent_buffer(extent_root->commit_root); -fail_tree_root: - free_extent_buffer(tree_root->node); - free_extent_buffer(tree_root->commit_root); -fail_chunk_root: - free_extent_buffer(chunk_root->node); - free_extent_buffer(chunk_root->commit_root); + +fail_tree_roots: + free_root_pointers(fs_info, 1); + fail_sb_buffer: btrfs_stop_workers(&fs_info->generic_worker); btrfs_stop_workers(&fs_info->fixup_workers); @@ -2164,6 +2389,25 @@ struct btrfs_root *open_ctree(struct super_block *sb, fail: free_fs_info(fs_info); return ERR_PTR(err); + +recovery_tree_root: + + if (!btrfs_test_opt(tree_root, RECOVERY)) + goto fail_tree_roots; + + free_root_pointers(fs_info, 0); + + /* don't use the log in recovery mode, it won't be valid */ + btrfs_set_super_log_root(disk_super, 0); + + /* we can't trust the free space cache either */ + btrfs_set_opt(fs_info->mount_opt, CLEAR_CACHE); + + ret = next_root_backup(fs_info, fs_info->super_copy, + &num_backups_tried, &backup_index); + if (ret == -1) + goto fail_block_groups; + goto retry_root_backup; } static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate) @@ -2333,6 +2577,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1; do_barriers = !btrfs_test_opt(root, NOBARRIER); + backup_super_roots(root->fs_info); sb = root->fs_info->super_for_commit; dev_item = &sb->dev_item; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index f7e9de724ef2..57080dffdfc6 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -164,7 +164,7 @@ enum { Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, - Opt_inode_cache, Opt_no_space_cache, Opt_err, + Opt_inode_cache, Opt_no_space_cache, Opt_recovery, Opt_err, }; static match_table_t tokens = { @@ -198,6 +198,7 @@ static match_table_t tokens = { {Opt_defrag, "autodefrag"}, {Opt_inode_cache, "inode_cache"}, {Opt_no_space_cache, "no_space_cache"}, + {Opt_recovery, "recovery"}, {Opt_err, NULL}, }; @@ -392,6 +393,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) printk(KERN_INFO "btrfs: enabling auto defrag"); btrfs_set_opt(info->mount_opt, AUTO_DEFRAG); break; + case Opt_recovery: + printk(KERN_INFO "btrfs: enabling auto recovery"); + btrfs_set_opt(info->mount_opt, RECOVERY); + break; case Opt_err: printk(KERN_INFO "btrfs: unrecognized mount option " "'%s'\n", p); From 6d668dda0caec537fbf28c4d91e6d18181af3cff Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 3 Nov 2011 22:54:25 -0400 Subject: [PATCH 1512/1596] Btrfs: make a delayed_block_rsv for the delayed item insertion I've been hitting warnings in use_block_rsv when running the delayed insertion stuff. It's because we will readjust global block rsv based on what is in use, which means we could end up discarding reservations that are for the delayed insertion stuff. So instead create a seperate block rsv for the delayed insertion stuff. This will also make it easier to debug problems with the delayed insertion reservations since we will know that only the delayed insertion code touches this block_rsv. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/ctree.h | 2 ++ fs/btrfs/delayed-inode.c | 14 +++++++------- fs/btrfs/disk-io.c | 1 + fs/btrfs/extent-tree.c | 3 +++ 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 78f43d1102a0..3002e5d4da0b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -957,6 +957,8 @@ struct btrfs_fs_info { struct btrfs_block_rsv trans_block_rsv; /* block reservation for chunk tree */ struct btrfs_block_rsv chunk_block_rsv; + /* block reservation for delayed operations */ + struct btrfs_block_rsv delayed_block_rsv; struct btrfs_block_rsv empty_block_rsv; diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index b52c672f4c18..fc4026af7290 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -591,7 +591,7 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans, return 0; src_rsv = trans->block_rsv; - dst_rsv = &root->fs_info->global_block_rsv; + dst_rsv = &root->fs_info->delayed_block_rsv; num_bytes = btrfs_calc_trans_metadata_size(root, 1); ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes); @@ -609,7 +609,7 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root, if (!item->bytes_reserved) return; - rsv = &root->fs_info->global_block_rsv; + rsv = &root->fs_info->delayed_block_rsv; btrfs_block_rsv_release(root, rsv, item->bytes_reserved); } @@ -628,7 +628,7 @@ static int btrfs_delayed_inode_reserve_metadata( return 0; src_rsv = trans->block_rsv; - dst_rsv = &root->fs_info->global_block_rsv; + dst_rsv = &root->fs_info->delayed_block_rsv; num_bytes = btrfs_calc_trans_metadata_size(root, 1); ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes); @@ -646,7 +646,7 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root, if (!node->bytes_reserved) return; - rsv = &root->fs_info->global_block_rsv; + rsv = &root->fs_info->delayed_block_rsv; btrfs_block_rsv_release(root, rsv, node->bytes_reserved); node->bytes_reserved = 0; @@ -1026,7 +1026,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, path->leave_spinning = 1; block_rsv = trans->block_rsv; - trans->block_rsv = &root->fs_info->global_block_rsv; + trans->block_rsv = &root->fs_info->delayed_block_rsv; delayed_root = btrfs_get_delayed_root(root); @@ -1069,7 +1069,7 @@ static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, path->leave_spinning = 1; block_rsv = trans->block_rsv; - trans->block_rsv = &node->root->fs_info->global_block_rsv; + trans->block_rsv = &node->root->fs_info->delayed_block_rsv; ret = btrfs_insert_delayed_items(trans, path, node->root, node); if (!ret) @@ -1149,7 +1149,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work) goto free_path; block_rsv = trans->block_rsv; - trans->block_rsv = &root->fs_info->global_block_rsv; + trans->block_rsv = &root->fs_info->delayed_block_rsv; ret = btrfs_insert_delayed_items(trans, path, root, delayed_node); if (!ret) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a61f8a6cf219..23b6776477b7 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1891,6 +1891,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, btrfs_init_block_rsv(&fs_info->trans_block_rsv); btrfs_init_block_rsv(&fs_info->chunk_block_rsv); btrfs_init_block_rsv(&fs_info->empty_block_rsv); + btrfs_init_block_rsv(&fs_info->delayed_block_rsv); atomic_set(&fs_info->nr_async_submits, 0); atomic_set(&fs_info->async_delalloc_pages, 0); atomic_set(&fs_info->async_submit_draining, 0); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 782eb3ea8edf..01c1f08b976a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3914,6 +3914,7 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info) fs_info->delalloc_block_rsv.space_info = space_info; fs_info->trans_block_rsv.space_info = space_info; fs_info->empty_block_rsv.space_info = space_info; + fs_info->delayed_block_rsv.space_info = space_info; fs_info->extent_root->block_rsv = &fs_info->global_block_rsv; fs_info->csum_root->block_rsv = &fs_info->global_block_rsv; @@ -3933,6 +3934,8 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info) WARN_ON(fs_info->trans_block_rsv.reserved > 0); WARN_ON(fs_info->chunk_block_rsv.size > 0); WARN_ON(fs_info->chunk_block_rsv.reserved > 0); + WARN_ON(fs_info->delayed_block_rsv.size > 0); + WARN_ON(fs_info->delayed_block_rsv.reserved > 0); } void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, From 663350ac38c67ca388acea6e876dc6d668c232b0 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 3 Nov 2011 22:54:25 -0400 Subject: [PATCH 1513/1596] Btrfs: be smarter about committing the transaction in reserve_metadata_bytes Because of the overcommit stuff I had to make it so that we committed the transaction all the time in reserve_metadata_bytes in case we had overcommitted because of delayed items. This was because previously we had no way of knowing how much space was reserved for delayed items. Now that we have the delayed_block_rsv we can check it to see if committing the transaction would get us anywhere. This patch breaks out the committing logic into a helper function that will check to see if committing the transaction would free enough space for us to get anything done. With this patch xfstests 83 goes from taking 445 seconds to taking 28 seconds on my box. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/extent-tree.c | 86 ++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 01c1f08b976a..5b84205e7685 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3334,12 +3334,12 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, /* * shrink metadata reservation for delalloc */ -static int shrink_delalloc(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 to_reclaim, +static int shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, bool wait_ordered) { struct btrfs_block_rsv *block_rsv; struct btrfs_space_info *space_info; + struct btrfs_trans_handle *trans; u64 reserved; u64 max_reclaim; u64 reclaimed = 0; @@ -3348,6 +3348,7 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans, int loops = 0; unsigned long progress; + trans = (struct btrfs_trans_handle *)current->journal_info; block_rsv = &root->fs_info->delalloc_block_rsv; space_info = block_rsv->space_info; @@ -3417,6 +3418,60 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans, return reclaimed >= to_reclaim; } +/** + * maybe_commit_transaction - possibly commit the transaction if its ok to + * @root - the root we're allocating for + * @bytes - the number of bytes we want to reserve + * @force - force the commit + * + * This will check to make sure that committing the transaction will actually + * get us somewhere and then commit the transaction if it does. Otherwise it + * will return -ENOSPC. + */ +static int may_commit_transaction(struct btrfs_root *root, + struct btrfs_space_info *space_info, + u64 bytes, int force) +{ + struct btrfs_block_rsv *delayed_rsv = &root->fs_info->delayed_block_rsv; + struct btrfs_trans_handle *trans; + + trans = (struct btrfs_trans_handle *)current->journal_info; + if (trans) + return -EAGAIN; + + if (force) + goto commit; + + /* See if there is enough pinned space to make this reservation */ + spin_lock(&space_info->lock); + if (space_info->bytes_pinned >= bytes) { + spin_unlock(&space_info->lock); + goto commit; + } + spin_unlock(&space_info->lock); + + /* + * See if there is some space in the delayed insertion reservation for + * this reservation. + */ + if (space_info != delayed_rsv->space_info) + return -ENOSPC; + + spin_lock(&delayed_rsv->lock); + if (delayed_rsv->size < bytes) { + spin_unlock(&delayed_rsv->lock); + return -ENOSPC; + } + spin_unlock(&delayed_rsv->lock); + +commit: + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) + return -ENOSPC; + + return btrfs_commit_transaction(trans, root); +} + /** * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space * @root - the root we're allocating for @@ -3436,7 +3491,6 @@ static int reserve_metadata_bytes(struct btrfs_root *root, u64 orig_bytes, int flush) { struct btrfs_space_info *space_info = block_rsv->space_info; - struct btrfs_trans_handle *trans; u64 used; u64 num_bytes = orig_bytes; int retries = 0; @@ -3445,7 +3499,6 @@ static int reserve_metadata_bytes(struct btrfs_root *root, bool flushing = false; bool wait_ordered = false; - trans = (struct btrfs_trans_handle *)current->journal_info; again: ret = 0; spin_lock(&space_info->lock); @@ -3461,7 +3514,7 @@ static int reserve_metadata_bytes(struct btrfs_root *root, * deadlock since we are waiting for the flusher to finish, but * hold the current transaction open. */ - if (trans) + if (current->journal_info) return -EAGAIN; ret = wait_event_interruptible(space_info->wait, !space_info->flush); @@ -3517,12 +3570,16 @@ static int reserve_metadata_bytes(struct btrfs_root *root, */ avail = (space_info->total_bytes - space_info->bytes_used) * 8; do_div(avail, 10); - if (space_info->bytes_pinned >= avail && flush && !trans && - !committed) { + if (space_info->bytes_pinned >= avail && flush && !committed) { space_info->flush = 1; flushing = true; spin_unlock(&space_info->lock); - goto commit; + ret = may_commit_transaction(root, space_info, + orig_bytes, 1); + if (ret) + goto out; + committed = true; + goto again; } spin_lock(&root->fs_info->free_chunk_lock); @@ -3575,7 +3632,7 @@ static int reserve_metadata_bytes(struct btrfs_root *root, * We do synchronous shrinking since we don't actually unreserve * metadata until after the IO is completed. */ - ret = shrink_delalloc(trans, root, num_bytes, wait_ordered); + ret = shrink_delalloc(root, num_bytes, wait_ordered); if (ret < 0) goto out; @@ -3592,21 +3649,12 @@ static int reserve_metadata_bytes(struct btrfs_root *root, goto again; } - ret = -EAGAIN; - if (trans) - goto out; - -commit: ret = -ENOSPC; if (committed) goto out; - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - goto out; - ret = btrfs_commit_transaction(trans, root); + ret = may_commit_transaction(root, space_info, orig_bytes, 0); if (!ret) { - trans = NULL; committed = true; goto again; } From bf0da8c183a15656eee63c54f334c3794320872a Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 4 Nov 2011 12:29:37 -0400 Subject: [PATCH 1514/1596] Btrfs: ClearPageError during writepage and clean_tree_block Failure testing was tripping up over stale PageError bits in metadata pages. If we have an io error on a block, and later on end up reusing it, nobody ever clears PageError on those pages. During commit, we'll find PageError and think we had trouble writing the block, which will lead to aborts and other problems. This changes clean_tree_block and the btrfs writepage code to clear the PageError bit. In both cases we're either completely done with the page or the page has good stuff and the error bit is no longer valid. Signed-off-by: Chris Mason --- fs/btrfs/extent_io.c | 4 ++++ fs/btrfs/transaction.c | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index b40ba75f4483..cc3c58970d4e 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2334,6 +2334,9 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, trace___extent_writepage(page, inode, wbc); WARN_ON(!PageLocked(page)); + + ClearPageError(page); + pg_offset = i_size & (PAGE_CACHE_SIZE - 1); if (page->index > end_index || (page->index == end_index && !pg_offset)) { @@ -3402,6 +3405,7 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree, PAGECACHE_TAG_DIRTY); } spin_unlock_irq(&page->mapping->tree_lock); + ClearPageError(page); unlock_page(page); } return 0; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 373c7ec1a026..29f782cc2cc9 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -634,7 +634,12 @@ int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, ret = btrfs_write_marked_extents(root, dirty_pages, mark); ret2 = btrfs_wait_marked_extents(root, dirty_pages, mark); - return ret || ret2; + + if (ret) + return ret; + if (ret2) + return ret2; + return 0; } int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, From c06a0e120a4e381a1c291c1fce3c6155c5791cae Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 4 Nov 2011 19:56:02 -0400 Subject: [PATCH 1515/1596] Btrfs: fix delayed insertion reservation We all keep getting those stupid warnings from use_block_rsv when running stress.sh, and it's because the delayed insertion stuff is being stupid. It's not the delayed insertion stuffs fault, it's all just stupid. When marking an inode dirty for oh say updating the time on it, we just do a btrfs_join_transaction, which doesn't reserve any space. This is stupid because we're going to have to have space reserve to make this change, but we do it because it's fast because chances are we're going to call it over and over again and it doesn't matter. Well thanks to the delayed insertion stuff this is mostly the case, so we do actually need to make this reservation. So if trans->bytes_reserved is 0 then try to do a normal reservation. If not return ENOSPC which will make the btrfs_dirty_inode start a proper transaction which will let it do the whole ENOSPC dance and reserve enough space for the delayed insertion to steal the reservation from the transaction. The other stupid thing we do is not reserve space for the inode when writing to the thing. Usually this is ok since we have to update the time so we'd have already done all this work before we get to the endio stuff, so it doesn't matter. But this is stupid because we could write the data after the transaction commits where we changed the mtime of the inode so we have to cow all the way down to the inode anyway. This used to be masked by the delalloc reservation stuff, but because we delay the update it doesn't get masked in this case. So again the delayed insertion stuff bites us in the ass. So if our trans->block_rsv is delalloc, just steal the reservation from the delalloc reserve. Hopefully this won't bite us in the ass, but I've said that before. With this patch stress.sh no longer spits out those stupid warnings (famous last words). Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason --- fs/btrfs/ctree.h | 3 +++ fs/btrfs/delayed-inode.c | 36 ++++++++++++++++++++++++++++-------- fs/btrfs/extent-tree.c | 18 ++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3002e5d4da0b..6bb34fc1ff22 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2353,6 +2353,9 @@ void btrfs_free_block_rsv(struct btrfs_root *root, int btrfs_block_rsv_add(struct btrfs_root *root, struct btrfs_block_rsv *block_rsv, u64 num_bytes); +int btrfs_block_rsv_add_noflush(struct btrfs_root *root, + struct btrfs_block_rsv *block_rsv, + u64 num_bytes); int btrfs_block_rsv_check(struct btrfs_root *root, struct btrfs_block_rsv *block_rsv, int min_factor); int btrfs_block_rsv_refill(struct btrfs_root *root, diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index fc4026af7290..bbe8496d5339 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -624,13 +624,36 @@ static int btrfs_delayed_inode_reserve_metadata( u64 num_bytes; int ret; - if (!trans->bytes_reserved) - return 0; - src_rsv = trans->block_rsv; dst_rsv = &root->fs_info->delayed_block_rsv; num_bytes = btrfs_calc_trans_metadata_size(root, 1); + + /* + * btrfs_dirty_inode will update the inode under btrfs_join_transaction + * which doesn't reserve space for speed. This is a problem since we + * still need to reserve space for this update, so try to reserve the + * space. + * + * Now if src_rsv == delalloc_block_rsv we'll let it just steal since + * we're accounted for. + */ + if (!trans->bytes_reserved && + src_rsv != &root->fs_info->delalloc_block_rsv) { + ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes); + /* + * Since we're under a transaction reserve_metadata_bytes could + * try to commit the transaction which will make it return + * EAGAIN to make us stop the transaction we have, so return + * ENOSPC instead so that btrfs_dirty_inode knows what to do. + */ + if (ret == -EAGAIN) + ret = -ENOSPC; + if (!ret) + node->bytes_reserved = num_bytes; + return ret; + } + ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes); if (!ret) node->bytes_reserved = num_bytes; @@ -1686,11 +1709,8 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, } ret = btrfs_delayed_inode_reserve_metadata(trans, root, delayed_node); - /* - * we must reserve enough space when we start a new transaction, - * so reserving metadata failure is impossible - */ - BUG_ON(ret); + if (ret) + goto release_node; fill_stack_inode_item(trans, &delayed_node->inode_item, inode); delayed_node->inode_dirty = 1; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5b84205e7685..23e936c3de76 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3814,6 +3814,24 @@ int btrfs_block_rsv_add(struct btrfs_root *root, return ret; } +int btrfs_block_rsv_add_noflush(struct btrfs_root *root, + struct btrfs_block_rsv *block_rsv, + u64 num_bytes) +{ + int ret; + + if (num_bytes == 0) + return 0; + + ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 0); + if (!ret) { + block_rsv_add_bytes(block_rsv, num_bytes, 1); + return 0; + } + + return ret; +} + int btrfs_block_rsv_check(struct btrfs_root *root, struct btrfs_block_rsv *block_rsv, int min_factor) { From 740c3d226cbba6cd6a32adfb66809c94938f3e57 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Wed, 2 Nov 2011 15:48:34 -0400 Subject: [PATCH 1516/1596] Btrfs: fix the new inspection ioctls for 32 bit compat The new ioctls to follow backrefs are not clean for 32/64 bit compat. This reworks them for u64s everywhere. They are brand new, so there are no problems with changing the interface now. Signed-off-by: Chris Mason --- fs/btrfs/backref.c | 8 ++++---- fs/btrfs/ioctl.c | 10 +++++----- fs/btrfs/ioctl.h | 11 +++++------ fs/btrfs/scrub.c | 2 +- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 2351df0de450..8855aad3929c 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -676,14 +676,14 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, bytes_left = ipath->fspath->bytes_left > s_ptr ? ipath->fspath->bytes_left - s_ptr : 0; - fspath_min = (char *)ipath->fspath->str + (i + 1) * s_ptr; + fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr; fspath = iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb, inum, fspath_min, bytes_left); if (IS_ERR(fspath)) return PTR_ERR(fspath); if (fspath > fspath_min) { - ipath->fspath->str[i] = fspath; + ipath->fspath->val[i] = (u64)fspath; ++ipath->fspath->elem_cnt; ipath->fspath->bytes_left = fspath - fspath_min; } else { @@ -698,9 +698,9 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, /* * this dumps all file system paths to the inode into the ipath struct, provided * is has been created large enough. each path is zero-terminated and accessed - * from ipath->fspath->str[i]. + * from ipath->fspath->val[i]. * when it returns, there are ipath->fspath->elem_cnt number of paths available - * in ipath->fspath->str[]. when the allocated space wasn't sufficient, the + * in ipath->fspath->val[]. when the allocated space wasn't sufficient, the * number of missed paths in recored in ipath->fspath->elem_missed, otherwise, * it's zero. ipath->fspath->bytes_missing holds the number of bytes that would * have been needed to return all paths. diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index cc9893990341..4a34c472f126 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2895,7 +2895,7 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) { int ret = 0; int i; - unsigned long rel_ptr; + u64 rel_ptr; int size; struct btrfs_ioctl_ino_path_args *ipa = NULL; struct inode_fs_paths *ipath = NULL; @@ -2930,11 +2930,11 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) goto out; for (i = 0; i < ipath->fspath->elem_cnt; ++i) { - rel_ptr = ipath->fspath->str[i] - (char *)ipath->fspath->str; - ipath->fspath->str[i] = (void *)rel_ptr; + rel_ptr = ipath->fspath->val[i] - (u64)ipath->fspath->val; + ipath->fspath->val[i] = rel_ptr; } - ret = copy_to_user(ipa->fspath, ipath->fspath, size); + ret = copy_to_user((void *)ipa->fspath, (void *)ipath->fspath, size); if (ret) { ret = -EFAULT; goto out; @@ -3017,7 +3017,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, if (ret < 0) goto out; - ret = copy_to_user(loi->inodes, inodes, size); + ret = copy_to_user((void *)loi->inodes, (void *)inodes, size); if (ret) ret = -EFAULT; diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 2da30d4950e6..252ae9915de8 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h @@ -198,24 +198,23 @@ struct btrfs_data_container { __u32 bytes_missing; /* out -- additional bytes needed for result */ __u32 elem_cnt; /* out */ __u32 elem_missed; /* out */ - union { - char *str[0]; /* out */ - __u64 val[0]; /* out */ - }; + __u64 val[0]; /* out */ }; struct btrfs_ioctl_ino_path_args { __u64 inum; /* in */ __u32 size; /* in */ __u64 reserved[4]; - struct btrfs_data_container *fspath; /* out */ + /* struct btrfs_data_container *fspath; out */ + __u64 fspath; /* out */ }; struct btrfs_ioctl_logical_ino_args { __u64 logical; /* in */ __u32 size; /* in */ __u64 reserved[4]; - struct btrfs_data_container *inodes; /* out */ + /* struct btrfs_data_container *inodes; out */ + __u64 inodes; }; #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 94cd3a19e9c8..562dad10dee9 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -272,7 +272,7 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx) swarn->logical, swarn->dev->name, (unsigned long long)swarn->sector, root, inum, offset, min(isize - offset, (u64)PAGE_SIZE), nlink, - ipath->fspath->str[i]); + (char *)ipath->fspath->val[i]); free_ipath(ipath); return 0; From c674e04e1cd6049715e7b9446790f4b441e547c0 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 3 Nov 2011 22:23:13 -0400 Subject: [PATCH 1517/1596] Btrfs: fix extent_buffer leak in the metadata IO error handling The scrub readahead branch brought in a new error handling hook, but it was leaking extent_buffer references. Signed-off-by: Chris Mason --- fs/btrfs/disk-io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0eb1f0951251..40a62b980087 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -644,6 +644,7 @@ static int btree_io_failed_hook(struct bio *failed_bio, clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags); btree_readahead_hook(root, eb, eb->start, -EIO); } + free_extent_buffer(eb); out: return -EIO; /* we fixed nothing */ From 306c8b68c82dfe6b7c9e5b61985760ad5d089205 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 3 Nov 2011 15:21:39 -0400 Subject: [PATCH 1518/1596] Btrfs: stop the readahead threads on failed mount If we don't stop them, they linger around corrupting memory by using pointers to freed things. Signed-off-by: Chris Mason --- fs/btrfs/disk-io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 40a62b980087..e532892431f4 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2444,6 +2444,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, fail_sb_buffer: btrfs_stop_workers(&fs_info->generic_worker); + btrfs_stop_workers(&fs_info->readahead_workers); btrfs_stop_workers(&fs_info->fixup_workers); btrfs_stop_workers(&fs_info->delalloc_workers); btrfs_stop_workers(&fs_info->workers); From 9510dc4c62252e96dca44a94948327c76774f25b Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 4 Nov 2011 09:41:02 -0400 Subject: [PATCH 1519/1596] Btrfs: stop leaking btrfs_bios on readahead Signed-off-by: Chris Mason --- fs/btrfs/reada.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index cd857119ba8a..35eaf6893679 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -423,6 +423,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, } spin_unlock(&fs_info->reada_lock); + kfree(multi); return re; error: @@ -447,6 +448,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, kref_put(&zone->refcnt, reada_zone_release); spin_unlock(&fs_info->reada_lock); } + kfree(multi); kfree(re); if (looped) goto again; From 21ca543efc12674fddb22ddf4ea4906427f4e982 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 4 Nov 2011 09:41:02 -0400 Subject: [PATCH 1520/1596] Btrfs: rename btrfs_bio multi -> bbio for consistency Signed-off-by: Chris Mason --- fs/btrfs/reada.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 35eaf6893679..2373b39a132b 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -247,7 +247,7 @@ int btree_readahead_hook(struct btrfs_root *root, struct extent_buffer *eb, static struct reada_zone *reada_find_zone(struct btrfs_fs_info *fs_info, struct btrfs_device *dev, u64 logical, - struct btrfs_bio *multi) + struct btrfs_bio *bbio) { int ret; int looped = 0; @@ -297,11 +297,11 @@ static struct reada_zone *reada_find_zone(struct btrfs_fs_info *fs_info, kref_init(&zone->refcnt); zone->elems = 0; zone->device = dev; /* our device always sits at index 0 */ - for (i = 0; i < multi->num_stripes; ++i) { + for (i = 0; i < bbio->num_stripes; ++i) { /* bounds have already been checked */ - zone->devs[i] = multi->stripes[i].dev; + zone->devs[i] = bbio->stripes[i].dev; } - zone->ndevs = multi->num_stripes; + zone->ndevs = bbio->num_stripes; spin_lock(&fs_info->reada_lock); ret = radix_tree_insert(&dev->reada_zones, @@ -327,7 +327,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, struct reada_extent *re = NULL; struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; - struct btrfs_bio *multi = NULL; + struct btrfs_bio *bbio = NULL; struct btrfs_device *dev; u32 blocksize; u64 length; @@ -361,21 +361,21 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, * map block */ length = blocksize; - ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length, &multi, 0); - if (ret || !multi || length < blocksize) + ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length, &bbio, 0); + if (ret || !bbio || length < blocksize) goto error; - if (multi->num_stripes > MAX_MIRRORS) { + if (bbio->num_stripes > MAX_MIRRORS) { printk(KERN_ERR "btrfs readahead: more than %d copies not " "supported", MAX_MIRRORS); goto error; } - for (nzones = 0; nzones < multi->num_stripes; ++nzones) { + for (nzones = 0; nzones < bbio->num_stripes; ++nzones) { struct reada_zone *zone; - dev = multi->stripes[nzones].dev; - zone = reada_find_zone(fs_info, dev, logical, multi); + dev = bbio->stripes[nzones].dev; + zone = reada_find_zone(fs_info, dev, logical, bbio); if (!zone) break; @@ -407,11 +407,11 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, goto error; } for (i = 0; i < nzones; ++i) { - dev = multi->stripes[i].dev; + dev = bbio->stripes[i].dev; ret = radix_tree_insert(&dev->reada_extents, index, re); if (ret) { while (--i >= 0) { - dev = multi->stripes[i].dev; + dev = bbio->stripes[i].dev; BUG_ON(dev == NULL); radix_tree_delete(&dev->reada_extents, index); } @@ -423,7 +423,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, } spin_unlock(&fs_info->reada_lock); - kfree(multi); + kfree(bbio); return re; error: @@ -448,7 +448,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, kref_put(&zone->refcnt, reada_zone_release); spin_unlock(&fs_info->reada_lock); } - kfree(multi); + kfree(bbio); kfree(re); if (looped) goto again; From 56d2a48f81a1bde827c625b90221fade72fe9c61 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 4 Nov 2011 09:41:02 -0400 Subject: [PATCH 1521/1596] Btrfs: fix a potential btrfs_bio leak on scrub fixups In case we were able to map less than we wanted (length < PAGE_SIZE clause is true) btrfs_bio is still allocated and we have to free it. Signed-off-by: Ilya Dryomov Signed-off-by: Chris Mason --- fs/btrfs/scrub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 562dad10dee9..ed11d3866afd 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -655,6 +655,7 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) "scrub_fixup: btrfs_map_block failed us for %llu\n", (unsigned long long)logical); WARN_ON(1); + kfree(bbio); return; } From d43317dcd074818d4bd12ddd4184a29aff98907b Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sun, 6 Nov 2011 03:26:19 -0500 Subject: [PATCH 1522/1596] Btrfs: fix race during transaction joins While we're allocating ram for a new transaction, we drop our spinlock. When we get the lock back, we do check to see if a transaction started while we slept, but we don't check to make sure it isn't blocked because a commit has already started. Signed-off-by: Chris Mason --- fs/btrfs/transaction.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 29f782cc2cc9..960835eaf4da 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -55,6 +55,7 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail) struct btrfs_transaction *cur_trans; spin_lock(&root->fs_info->trans_lock); +loop: if (root->fs_info->trans_no_join) { if (!nofail) { spin_unlock(&root->fs_info->trans_lock); @@ -75,16 +76,18 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail) cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); if (!cur_trans) return -ENOMEM; + spin_lock(&root->fs_info->trans_lock); if (root->fs_info->running_transaction) { + /* + * someone started a transaction after we unlocked. Make sure + * to redo the trans_no_join checks above + */ kmem_cache_free(btrfs_transaction_cachep, cur_trans); cur_trans = root->fs_info->running_transaction; - atomic_inc(&cur_trans->use_count); - atomic_inc(&cur_trans->num_writers); - cur_trans->num_joined++; - spin_unlock(&root->fs_info->trans_lock); - return 0; + goto loop; } + atomic_set(&cur_trans->num_writers, 1); cur_trans->num_joined = 0; init_waitqueue_head(&cur_trans->writer_wait); From 862a6244eb9f9f5123fe819454fcfcae0ee1f2f9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sat, 15 Oct 2011 23:19:25 +0200 Subject: [PATCH 1523/1596] ALSA: ua101: fix crash when unplugging If the device is unplugged while running, it is possible for a PCM device to be closed after the disconnect callback has returned. This means that kill_stream_urb() and disable_iso_interface() would try to access already-invalid or freed USB data structures. The function free_usb_related_resources() was intended to prevent this, but forgot to clear the affected variables. Reported-and-tested-by: Olivier Courtay Signed-off-by: Clemens Ladisch Cc: 2.6.33+ Signed-off-by: Takashi Iwai --- sound/usb/misc/ua101.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 67bec7612442..c0609c210303 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua101_stream *stream) unsigned int i; for (i = 0; i < stream->queue_length; ++i) - usb_kill_urb(&stream->urbs[i]->urb); + if (stream->urbs[i]) + usb_kill_urb(&stream->urbs[i]->urb); } static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) @@ -484,6 +485,9 @@ static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index) { struct usb_host_interface *alts; + if (!ua->intf[intf_index]) + return; + alts = ua->intf[intf_index]->cur_altsetting; if (alts->desc.bAlternateSetting != 0) { int err = usb_set_interface(ua->dev, @@ -1144,27 +1148,37 @@ static void free_stream_urbs(struct ua101_stream *stream) { unsigned int i; - for (i = 0; i < stream->queue_length; ++i) + for (i = 0; i < stream->queue_length; ++i) { kfree(stream->urbs[i]); + stream->urbs[i] = NULL; + } } static void free_usb_related_resources(struct ua101 *ua, struct usb_interface *interface) { unsigned int i; + struct usb_interface *intf; + mutex_lock(&ua->mutex); free_stream_urbs(&ua->capture); free_stream_urbs(&ua->playback); + mutex_unlock(&ua->mutex); free_stream_buffers(ua, &ua->capture); free_stream_buffers(ua, &ua->playback); - for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) - if (ua->intf[i]) { - usb_set_intfdata(ua->intf[i], NULL); - if (ua->intf[i] != interface) + for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) { + mutex_lock(&ua->mutex); + intf = ua->intf[i]; + ua->intf[i] = NULL; + mutex_unlock(&ua->mutex); + if (intf) { + usb_set_intfdata(intf, NULL); + if (intf != interface) usb_driver_release_interface(&ua101_driver, - ua->intf[i]); + intf); } + } } static void ua101_card_free(struct snd_card *card) From 447c6f93aba42e6889be55a614d4dddc25f17863 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 5 Nov 2011 22:51:54 +0100 Subject: [PATCH 1524/1596] ALSA: control: remove compilation warning on 32-bit This was introduced by 'ALSA: control: add support for ENUMERATED user space controls' which adds a u64 variable that gets cast to a pointer: sound/core/control.c: In function 'snd_ctl_elem_init_enum_names': sound/core/control.c:1089: warning: cast to pointer from integer of different size Cast to uintptr_t before casting to pointer to avoid the warning. Signed-off-by: Olof Johansson [cl: replace long with uintptr_t] Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/control.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 978fe1a8e9f0..59edb12dd542 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1081,12 +1081,12 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) char *names, *p; size_t buf_len, name_len; unsigned int i; + const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr; if (ue->info.value.enumerated.names_length > 64 * 1024) return -EINVAL; - names = memdup_user( - (const void __user *)ue->info.value.enumerated.names_ptr, + names = memdup_user((const void __user *)user_ptrval, ue->info.value.enumerated.names_length); if (IS_ERR(names)) return PTR_ERR(names); From 43dea228a3ba5463392281535dfb3d3fe56f4c2c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 6 Nov 2011 11:25:34 +0100 Subject: [PATCH 1525/1596] ALSA: hda - Fix silent output regression with ALC861 The 3.1 kernel has a regression for ALC861 codec where no sound output is heard with the default setup. It's because the amps in DACs aren't properly unmuted while the output mixers are assigned only to pins. This patch fixes the missing initialization of DACs when no mixer is assigned to them. Tested-by: Andrea Iob Cc: [v3.1+] Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 80d6add8a620..9693059dec84 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3329,6 +3329,12 @@ static void alc_auto_set_output_and_unmute(struct hda_codec *codec, if (nid) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); + + /* unmute DAC if it's not assigned to a mixer */ + nid = alc_look_for_out_mute_nid(codec, pin, dac); + if (nid == mix && nid_has_mute(codec, dac, HDA_OUTPUT)) + snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_ZERO); } static void alc_auto_init_multi_out(struct hda_codec *codec) From 69f9ba9b0cad67bc03f0a096f7f274de795ca844 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 6 Nov 2011 13:49:13 +0100 Subject: [PATCH 1526/1596] ALSA: hda - Fix a regression for DMA-position check with CA0110 The regression-fix in 3.1 for the check of DMA-position validity caused yet another regression for CA0110. As usual, this hardware seems working only with LPIB properly. Adding the appropriate driver-caps bit to force LPIB fixes the problem. Reported-and-tested-by: Andres Freund Cc: [v3.1] Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bd7fc99af187..096507d2ca9a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -3063,12 +3063,12 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | - AZX_DCAPS_RIRB_PRE_DELAY }, + AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | - AZX_DCAPS_RIRB_PRE_DELAY }, + AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, #endif /* Vortex86MX */ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, From f441917256c9727d3573ca2f89f657a75e06a262 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 6 Nov 2011 14:01:58 +0100 Subject: [PATCH 1527/1596] ALSA: hda - Revert the check of NO_PRESENCE pincfg default bit The implementation on commit [08a1f5eb: ALSA: hda - Check NO_PRESENCE pincfg default bit] seems like a mis-interpretation of specification. The spec gives the reversed bit definition. But, following the spec also causes to change so many existing device configurations, thus we can't change it so easily for now. For 3.2-rc1, it's safer to revert this check (actually this patch comments out the code). We may re-introduced the fixed version once after the wider test-case coverages are done. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_local.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 79f49e2e8cbc..dcbea0da0fa2 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -511,8 +511,11 @@ int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) { return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) && - !(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid) & - AC_DEFCFG_MISC_NO_PRESENCE)) && + /* disable MISC_NO_PRESENCE check because it may break too + * many devices + */ + /*(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid) & + AC_DEFCFG_MISC_NO_PRESENCE)) &&*/ (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP); } From 2aba6cac2a84f3b80e11a680c34d55e7739b474d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 6 Nov 2011 20:25:18 +0100 Subject: [PATCH 1528/1596] hwmon: (coretemp) Fix for non-SMP builds The definition of TO_ATTR_NO in the non-SMP case is wrong. As the SMP definition resolves to the correct value, just use this for both cases. Without this fix the temperature attributes are named temp0_* instead of temp2_*, so libsensors won't pick them. Broken since kernel 3.0. Signed-off-by: Jean Delvare Tested-by: Phil Sutter Cc: stable@kernel.org Acked-by: Durgadoss R Acked-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index ce18c046f728..104b3767516c 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -60,14 +60,13 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); #ifdef CONFIG_SMP #define TO_PHYS_ID(cpu) cpu_data(cpu).phys_proc_id #define TO_CORE_ID(cpu) cpu_data(cpu).cpu_core_id -#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) #define for_each_sibling(i, cpu) for_each_cpu(i, cpu_sibling_mask(cpu)) #else #define TO_PHYS_ID(cpu) (cpu) #define TO_CORE_ID(cpu) (cpu) -#define TO_ATTR_NO(cpu) (cpu) #define for_each_sibling(i, cpu) for (i = 0; false; ) #endif +#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) /* * Per-Core Temperature Data From bfa02b0da66965caf46e441270af87edda4fea14 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 6 Nov 2011 20:25:18 +0100 Subject: [PATCH 1529/1596] hwmon: (w83627ehf) Fix broken driver init Commit 2265cef2 (hwmon: (w83627ehf) Properly report PECI and AMD-SI sensor types) results in kernel panic if data->temp_label was not initialized. The problem was found with chip W83627DHG-P. Add check if data->temp->label was set before use. Based on incomplete patch by Alexander Beregalov. Reported-by: Alexander Beregalov Tested-by: Alexander Beregalov Cc: stable@kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Jean Delvare --- drivers/hwmon/w83627ehf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 483cb268781e..93f5fc7d6059 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1835,12 +1835,15 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, diode = 0x70; } for (i = 0; i < 3; i++) { - const char *label = data->temp_label[data->temp_src[i]]; + const char *label = NULL; + + if (data->temp_label) + label = data->temp_label[data->temp_src[i]]; /* Digital source overrides analog type */ - if (strncmp(label, "PECI", 4) == 0) + if (label && strncmp(label, "PECI", 4) == 0) data->temp_type[i] = 6; - else if (strncmp(label, "AMD", 3) == 0) + else if (label && strncmp(label, "AMD", 3) == 0) data->temp_type[i] = 5; else if ((tmp & (0x02 << i))) data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3; From 1cd0d6c3021c8d76641b37203f504634b87fbabc Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 1 Nov 2011 03:59:33 +0000 Subject: [PATCH 1530/1596] module: Enable dynamic debugging regardless of taint Dynamic debugging is currently disabled for tainted modules, except for TAINT_CRAP. This prevents use of dynamic debugging for out-of-tree modules once the next patch is applied. This condition was apparently intended to avoid a crash if a force- loaded module has an incompatible definition of dynamic debug structures. However, a administrator that forces us to load a module is claiming that it *is* compatible even though it fails our version checks. If they are mistaken, there are any number of ways the module could crash the system. As a side-effect, proprietary and other tainted modules can now use dynamic_debug. Signed-off-by: Ben Hutchings Acked-by: Mathieu Desnoyers Signed-off-by: Rusty Russell --- kernel/module.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index 93342d992f34..3c5509642847 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2878,8 +2878,7 @@ static struct module *load_module(void __user *umod, } /* This has to be done once we're sure module name is unique. */ - if (!mod->taints || mod->taints == (1U<taints || mod->taints == (1U< Date: Mon, 24 Oct 2011 15:12:28 +0200 Subject: [PATCH 1531/1596] module,bug: Add TAINT_OOT_MODULE flag for modules not built in-tree Use of the GPL or a compatible licence doesn't necessarily make the code any good. We already consider staging modules to be suspect, and this should also be true for out-of-tree modules which may receive very little review. Signed-off-by: Ben Hutchings Reviewed-by: Dave Jones Acked-by: Greg Kroah-Hartman Signed-off-by: Rusty Russell (patched oops-tracing.txt) --- Documentation/oops-tracing.txt | 2 ++ include/linux/kernel.h | 1 + kernel/module.c | 5 +++++ kernel/panic.c | 2 ++ scripts/mod/modpost.c | 7 +++++++ 5 files changed, 17 insertions(+) diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index 6fe9001b9263..13032c0140d4 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -263,6 +263,8 @@ characters, each representing a particular tainted value. 12: 'I' if the kernel is working around a severe bug in the platform firmware (BIOS or similar). + 13: 'O' if an externally-built ("out-of-tree") module has been loaded. + The primary reason for the 'Tainted: ' string is to tell kernel debuggers if this is a clean kernel or if anything unusual has occurred. Tainting is permanent: even if an offending module is diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 4c0d3b2fd5fc..e8b1597b5cf2 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -371,6 +371,7 @@ extern enum system_states { #define TAINT_WARN 9 #define TAINT_CRAP 10 #define TAINT_FIRMWARE_WORKAROUND 11 +#define TAINT_OOT_MODULE 12 extern const char hex_asc[]; #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] diff --git a/kernel/module.c b/kernel/module.c index 3c5509642847..ef8cb70c6996 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2487,6 +2487,9 @@ static int check_modinfo(struct module *mod, struct load_info *info) return -ENOEXEC; } + if (!get_modinfo(info, "intree")) + add_taint_module(mod, TAINT_OOT_MODULE); + if (get_modinfo(info, "staging")) { add_taint_module(mod, TAINT_CRAP); printk(KERN_WARNING "%s: module is from the staging directory," @@ -3255,6 +3258,8 @@ static char *module_flags(struct module *mod, char *buf) buf[bx++] = '('; if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE)) buf[bx++] = 'P'; + else if (mod->taints & (1 << TAINT_OOT_MODULE)) + buf[bx++] = 'O'; if (mod->taints & (1 << TAINT_FORCED_MODULE)) buf[bx++] = 'F'; if (mod->taints & (1 << TAINT_CRAP)) diff --git a/kernel/panic.c b/kernel/panic.c index d7bb6974efb5..b26593604214 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -177,6 +177,7 @@ static const struct tnt tnts[] = { { TAINT_WARN, 'W', ' ' }, { TAINT_CRAP, 'C', ' ' }, { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' }, + { TAINT_OOT_MODULE, 'O', ' ' }, }; /** @@ -194,6 +195,7 @@ static const struct tnt tnts[] = { * 'W' - Taint on warning. * 'C' - modules from drivers/staging are loaded. * 'I' - Working around severe firmware bug. + * 'O' - Out-of-tree module has been loaded. * * The string is overwritten by the next call to print_tainted(). */ diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index a509ff8f32fa..2bd594e6d1b4 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1849,6 +1849,12 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "};\n"); } +static void add_intree_flag(struct buffer *b, int is_intree) +{ + if (is_intree) + buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); +} + static void add_staging_flag(struct buffer *b, const char *name) { static const char *staging_dir = "drivers/staging"; @@ -2169,6 +2175,7 @@ int main(int argc, char **argv) buf.pos = 0; add_header(&buf, mod); + add_intree_flag(&buf, !external_module); add_staging_flag(&buf, mod->name); err |= add_versions(&buf, mod); add_depends(&buf, mod, modules); From 22f4521d664030e417f41953e922f61c65f2e189 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 12 Aug 2011 00:13:47 -0400 Subject: [PATCH 1532/1596] mrst pmu: update comment referenced MeeGo, in particular, but really means Linux, in general. Signed-off-by: Len Brown --- arch/x86/platform/mrst/pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/platform/mrst/pmu.c b/arch/x86/platform/mrst/pmu.c index 9281da7d91bd..c0ac06da57ac 100644 --- a/arch/x86/platform/mrst/pmu.c +++ b/arch/x86/platform/mrst/pmu.c @@ -70,7 +70,7 @@ static struct mrst_device mrst_devs[] = { /* 24 */ { 0x4110, 0 }, /* Lincroft */ }; -/* n.b. We ignore PCI-id 0x815 in LSS9 b/c MeeGo has no driver for it */ +/* n.b. We ignore PCI-id 0x815 in LSS9 b/c Linux has no driver for it */ static u16 mrst_lss9_pci_ids[] = {0x080a, 0x0814, 0}; static u16 mrst_lss10_pci_ids[] = {0x0800, 0x0801, 0x0802, 0x0803, 0x0804, 0x0805, 0x080f, 0}; From 7c7e82a77fe3d89ae50824aa7c897454675eb4c4 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sun, 6 Nov 2011 18:50:56 -0500 Subject: [PATCH 1533/1596] Btrfs: check for a null fs root when writing to the backup root log During log replay, can commit the transaction before the fs_root pointers are setup, so we have to make sure they are not null before trying to use them. Signed-off-by: Chris Mason --- fs/btrfs/disk-io.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e532892431f4..e53a5bb85670 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1754,11 +1754,18 @@ static void backup_super_roots(struct btrfs_fs_info *info) btrfs_set_backup_extent_root_level(root_backup, btrfs_header_level(info->extent_root->node)); - btrfs_set_backup_fs_root(root_backup, info->fs_root->node->start); - btrfs_set_backup_fs_root_gen(root_backup, + /* + * we might commit during log recovery, which happens before we set + * the fs_root. Make sure it is valid before we fill it in. + */ + if (info->fs_root && info->fs_root->node) { + btrfs_set_backup_fs_root(root_backup, + info->fs_root->node->start); + btrfs_set_backup_fs_root_gen(root_backup, btrfs_header_generation(info->fs_root->node)); - btrfs_set_backup_fs_root_level(root_backup, + btrfs_set_backup_fs_root_level(root_backup, btrfs_header_level(info->fs_root->node)); + } btrfs_set_backup_dev_root(root_backup, info->dev_root->node->start); btrfs_set_backup_dev_root_gen(root_backup, From 581de59e8dff8eaa52809e768a585e9ef336aa4a Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Sat, 6 Aug 2011 11:32:56 +0200 Subject: [PATCH 1534/1596] ACPI: use kstrdup() Use kstrdup rather than duplicating its implementation The semantic patch that makes this output is available in scripts/coccinelle/api/kstrdup.cocci. More information about semantic patching is available at http://coccinelle.lip6.fr/ Signed-off-by: Thomas Meyer Signed-off-by: Len Brown --- drivers/acpi/scan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 449c556274c0..8ab80bafe3f1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1062,13 +1062,12 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id) if (!id) return; - id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); + id->id = kstrdup(dev_id, GFP_KERNEL); if (!id->id) { kfree(id); return; } - strcpy(id->id, dev_id); list_add_tail(&id->list, &device->pnp.ids); } From f7f71cfbf0c276ee3d8d856d0f35a41aed997fa4 Mon Sep 17 00:00:00 2001 From: Rakib Mullick Date: Sun, 6 Nov 2011 21:18:17 +0600 Subject: [PATCH 1535/1596] ACPI: Fix possible recursive locking in hwregs.c Calling pm-suspend might trigger a recursive lock in it's code path. In function acpi_hw_clear_acpi_status, acpi_os_acquire_lock holds the lock acpi_gbl_hardware_lock before calling acpi_hw_register_write(), then without releasing acpi_gbl_hardware_lock, this function calls acpi_ev_walk_gpe_list, which tries to hold acpi_gbl_gpe_lock. Both acpi_gbl_hardware_lock and acpi_gbl_gpe_lock are at same lock-class and which might cause lock recursion deadlock. Following patch fixes this scenario by just releasing acpi_gbl_hardware_lock before calling acpi_ev_walk_gpe_list. Changes since v0(https://lkml.org/lkml/2011/9/21/355): - Fix changelog, thanks to Lin Ming. Changes since v1 (https://lkml.org/lkml/2011/11/3/89): - Update changelog and rename goto label, courtesy Srivatsa S. Bhat. Signed-off-by: Rakib Mullick Reviewed-by: Srivatsa S. Bhat Acked-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/acpica/hwregs.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 55accb7018bb..cc70f3fdcdd1 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -269,16 +269,17 @@ acpi_status acpi_hw_clear_acpi_status(void) status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, ACPI_BITMASK_ALL_FIXED_STATUS); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } + + acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + + if (ACPI_FAILURE(status)) + goto exit; /* Clear the GPE Bits in all GPE registers in all GPE blocks */ status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); - unlock_and_exit: - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); +exit: return_ACPI_STATUS(status); } From 18fd470a48396c8795ba7256c5973e92ffa25cb3 Mon Sep 17 00:00:00 2001 From: Witold Szczeponik Date: Thu, 27 Oct 2011 20:56:47 +0200 Subject: [PATCH 1536/1596] PNPACPI: Simplify disabled resource registration The attached patch simplifies 29df8d8f8702f0f53c1375015f09f04bc8d023c1. As the "pnp_xxx" structs are not designed to cope with IORESOURCE_DISABLED, and hence no code can test for this value, setting this value is actually a "no op" and can be skipped altogether. It is sufficient to remove the checks for "empty" resources and continue processing. The patch is applied against 3.1. Signed-off-by: Witold Szczeponik Acked-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/rsparser.c | 62 ++++++++-------------------------- 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index bbf3edd85beb..5be4a392a3ae 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -509,15 +509,12 @@ static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, struct acpi_resource_dma *p) { int i; - unsigned char map = 0, flags = 0; - - if (p->channel_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char map = 0, flags; for (i = 0; i < p->channel_count; i++) map |= 1 << p->channels[i]; - flags |= dma_flags(dev, p->type, p->bus_master, p->transfer); + flags = dma_flags(dev, p->type, p->bus_master, p->transfer); pnp_register_dma_resource(dev, option_flags, map, flags); } @@ -527,17 +524,14 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, { int i; pnp_irq_mask_t map; - unsigned char flags = 0; - - if (p->interrupt_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char flags; bitmap_zero(map.bits, PNP_IRQ_NR); for (i = 0; i < p->interrupt_count; i++) if (p->interrupts[i]) __set_bit(p->interrupts[i], map.bits); - flags |= irq_flags(p->triggering, p->polarity, p->sharable); + flags = irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } @@ -547,10 +541,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, { int i; pnp_irq_mask_t map; - unsigned char flags = 0; - - if (p->interrupt_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char flags; bitmap_zero(map.bits, PNP_IRQ_NR); for (i = 0; i < p->interrupt_count; i++) { @@ -564,7 +555,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, } } - flags |= irq_flags(p->triggering, p->polarity, p->sharable); + flags = irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } @@ -574,11 +565,8 @@ static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (io->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (io->io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; + flags = IORESOURCE_IO_16BIT_ADDR; pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, io->alignment, io->address_length, flags); } @@ -587,13 +575,8 @@ static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, unsigned int option_flags, struct acpi_resource_fixed_io *io) { - unsigned char flags = 0; - - if (io->address_length == 0) - flags |= IORESOURCE_DISABLED; - pnp_register_port_resource(dev, option_flags, io->address, io->address, - 0, io->address_length, flags | IORESOURCE_IO_FIXED); + 0, io->address_length, IORESOURCE_IO_FIXED); } static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, @@ -602,11 +585,8 @@ static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, p->alignment, p->address_length, flags); } @@ -617,11 +597,8 @@ static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, p->alignment, p->address_length, flags); } @@ -632,11 +609,8 @@ static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->address, p->address, 0, p->address_length, flags); } @@ -656,19 +630,16 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, return; } - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) pnp_register_port_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, - flags | IORESOURCE_IO_FIXED); + IORESOURCE_IO_FIXED); } static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, @@ -678,19 +649,16 @@ static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, struct acpi_resource_extended_address64 *p = &r->data.ext_address64; unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) pnp_register_port_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, - flags | IORESOURCE_IO_FIXED); + IORESOURCE_IO_FIXED); } struct acpipnp_parse_option_s { From 3bf3f8b19d2bfccc40f13c456bf339fd8f535ebc Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Fri, 21 Oct 2011 14:42:55 -0700 Subject: [PATCH 1537/1596] ACPI atomicio: Convert width in bits to bytes in __acpi_ioremap_fast() Callers to __acpi_ioremap_fast() pass the bit_width that they found in the acpi_generic_address structure. Convert from bits to bytes when passing to __acpi_find_iomap() - as it wants to see bytes, not bits. cc: stable@kernel.org Signed-off-by: Tony Luck Signed-off-by: Len Brown --- drivers/acpi/atomicio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c index 7489b89c300f..f151afe61aab 100644 --- a/drivers/acpi/atomicio.c +++ b/drivers/acpi/atomicio.c @@ -76,7 +76,7 @@ static void __iomem *__acpi_ioremap_fast(phys_addr_t paddr, { struct acpi_iomap *map; - map = __acpi_find_iomap(paddr, size); + map = __acpi_find_iomap(paddr, size/8); if (map) return map->vaddr + (paddr - map->paddr); else From 4505a2015f4c4b2f21137cc3a6b7400b0f3e073e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 6 Nov 2011 14:20:42 +0100 Subject: [PATCH 1538/1596] ACPI: Drop ACPI_NO_HARDWARE_INIT ACPI_NO_HARDWARE_INIT is only used by acpi_early_init() and acpi_bus_init() when calling acpi_enable_subsystem(), but acpi_enable_subsystem() doesn't check that flag, so it can be dropped. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 8 ++------ include/acpi/actypes.h | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 437ddbf0c49a..9ecec98bc76e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -911,10 +911,7 @@ void __init acpi_early_init(void) } #endif - status = - acpi_enable_subsystem(~ - (ACPI_NO_HARDWARE_INIT | - ACPI_NO_ACPI_ENABLE)); + status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to enable ACPI\n"); goto error0; @@ -935,8 +932,7 @@ static int __init acpi_bus_init(void) acpi_os_initialize1(); - status = - acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE); + status = acpi_enable_subsystem(ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n"); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index b67231bef632..ed73f6705c86 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -470,7 +470,6 @@ typedef u64 acpi_integer; */ #define ACPI_FULL_INITIALIZATION 0x00 #define ACPI_NO_ADDRESS_SPACE_INIT 0x01 -#define ACPI_NO_HARDWARE_INIT 0x02 #define ACPI_NO_EVENT_INIT 0x04 #define ACPI_NO_HANDLER_INIT 0x08 #define ACPI_NO_ACPI_ENABLE 0x10 From 51e20d0e3a60cf46b52ee1af598a35834919ed27 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 6 Nov 2011 14:21:38 +0100 Subject: [PATCH 1539/1596] thermal: Prevent polling from happening during system suspend The thermal driver should use a freezable workqueue to schedule polling to prevent thermal_zone_device_update() from being run during system suspend, when the devices it relies on may be inactive. Make it use the system freezable workqueue for this purpose. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 708f8e92771a..dd9a5743fa99 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -678,10 +678,10 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, return; if (delay > 1000) - schedule_delayed_work(&(tz->poll_queue), + queue_delayed_work(system_freezable_wq, &(tz->poll_queue), round_jiffies(msecs_to_jiffies(delay))); else - schedule_delayed_work(&(tz->poll_queue), + queue_delayed_work(system_freezable_wq, &(tz->poll_queue), msecs_to_jiffies(delay)); } From 362b646062b2073bd5c38efb42171d86e4f717e6 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Fri, 4 Nov 2011 03:33:46 +0100 Subject: [PATCH 1540/1596] ACPI: Export FADT pm_profile integer value to userspace There are a lot userspace approaches to detect the usage of the platform (laptop, workstation, server, ...) and adjust kernel tunables accordingly (io/process scheduler, power management, ...). These approaches need constant maintaining and are ugly to implement (detect PCMCIA controller -> laptop, does not work on recent systems anymore, ...) On ACPI systems there is an easy and reliable way (if implemented in BIOS and most recent platforms have this value set). -> export it to userspace. Signed-off-by: Thomas Renninger Acked-by: Rafael J. Wysocki Signed-off-by: Len Brown --- Documentation/ABI/stable/sysfs-acpi-pmprofile | 22 +++++++++++++++++++ drivers/acpi/sysfs.c | 14 +++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/stable/sysfs-acpi-pmprofile diff --git a/Documentation/ABI/stable/sysfs-acpi-pmprofile b/Documentation/ABI/stable/sysfs-acpi-pmprofile new file mode 100644 index 000000000000..964c7a8afb26 --- /dev/null +++ b/Documentation/ABI/stable/sysfs-acpi-pmprofile @@ -0,0 +1,22 @@ +What: /sys/firmware/acpi/pm_profile +Date: 03-Nov-2011 +KernelVersion: v3.2 +Contact: linux-acpi@vger.kernel.org +Description: The ACPI pm_profile sysfs interface exports the platform + power management (and performance) requirement expectations + as provided by BIOS. The integer value is directly passed as + retrieved from the FADT ACPI table. +Values: For possible values see ACPI specification: + 5.2.9 Fixed ACPI Description Table (FADT) + Field: Preferred_PM_Profile + + Currently these values are defined by spec: + 0 Unspecified + 1 Desktop + 2 Mobile + 3 Workstation + 4 Enterprise Server + 5 SOHO Server + 6 Appliance PC + 7 Performance Server + >7 Reserved diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index c538d0ef10ff..9f66181c814e 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -706,11 +706,23 @@ static void __exit interrupt_stats_exit(void) return; } +static ssize_t +acpi_show_profile(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); +} + +static const struct device_attribute pm_profile_attr = + __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); + int __init acpi_sysfs_init(void) { int result; result = acpi_tables_sysfs_init(); - + if (result) + return result; + result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); return result; } From c1056b42a87b59375f8f81a92ef029165f44fcce Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 2 Nov 2011 20:16:05 +0100 Subject: [PATCH 1541/1596] ACPI: Fix CONFIG_ACPI_DOCK=n compiler warning Recently the ACPI ops structs were constified but the inline version of register_hotplug_dock_device() was overlooked (see also commit 9c8b04b, June 25 2011). Update the inline function register_hotplug_dock_device() that is enabled with CONFIG_ACPI_DOCK=n too. This patch fixes at least the following compiler warnings: drivers/ata/libata-acpi.c: In function .ata_acpi_associate.: drivers/ata/libata-acpi.c:266:11: warning: passing argument 2 of .register_hotplug_dock_device. discards qualifiers from pointer target type include/acpi/acpi_drivers.h:146:19: note: expected .struct acpi_dock_ops *. but argument is of type .const struct acpi_dock_ops *. drivers/ata/libata-acpi.c:275:11: warning: passing argument 2 of .register_hotplug_dock_device. discards qualifiers from pointer target type include/acpi/acpi_drivers.h:146:19: note: expected .struct acpi_dock_ops *. but argument is of type .const struct acpi_dock_ops *. Cc: stable@vger.kernel.org Signed-off-by: Len Brown --- include/acpi/acpi_drivers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index e49c36d38d7e..bb145e4b935e 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -144,7 +144,7 @@ static inline void unregister_dock_notifier(struct notifier_block *nb) { } static inline int register_hotplug_dock_device(acpi_handle handle, - struct acpi_dock_ops *ops, + const struct acpi_dock_ops *ops, void *context) { return -ENODEV; From e978aa7d7d57d04eb5f88a7507c4fb98577def77 Mon Sep 17 00:00:00 2001 From: Deepthi Dharwar Date: Fri, 28 Oct 2011 16:20:09 +0530 Subject: [PATCH 1542/1596] cpuidle: Move dev->last_residency update to driver enter routine; remove dev->last_state Cpuidle governor only suggests the state to enter using the governor->select() interface, but allows the low level driver to override the recommended state. The actual entered state may be different because of software or hardware demotion. Software demotion is done by the back-end cpuidle driver and can be accounted correctly. Current cpuidle code uses last_state field to capture the actual state entered and based on that updates the statistics for the state entered. Ideally the driver enter routine should update the counters, and it should return the state actually entered rather than the time spent there. The generic cpuidle code should simply handle where the counters live in the sysfs namespace, not updating the counters. Reference: https://lkml.org/lkml/2011/3/25/52 Signed-off-by: Deepthi Dharwar Signed-off-by: Trinabh Gupta Tested-by: Jean Pihet Reviewed-by: Kevin Hilman Acked-by: Arjan van de Ven Acked-by: Kevin Hilman Signed-off-by: Len Brown --- arch/arm/mach-at91/cpuidle.c | 10 ++-- arch/arm/mach-davinci/cpuidle.c | 9 ++-- arch/arm/mach-exynos4/cpuidle.c | 7 +-- arch/arm/mach-kirkwood/cpuidle.c | 12 +++-- arch/arm/mach-omap2/cpuidle34xx.c | 67 ++++++++++++++---------- arch/sh/kernel/cpu/shmobile/cpuidle.c | 12 +++-- drivers/acpi/processor_idle.c | 75 +++++++++++++++++---------- drivers/cpuidle/cpuidle.c | 32 ++++++------ drivers/cpuidle/governors/ladder.c | 13 +++++ drivers/cpuidle/governors/menu.c | 7 ++- drivers/idle/intel_idle.c | 12 +++-- include/linux/cpuidle.h | 7 ++- 12 files changed, 164 insertions(+), 99 deletions(-) diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c index 1cfeac1483d6..4696a0d61e2e 100644 --- a/arch/arm/mach-at91/cpuidle.c +++ b/arch/arm/mach-at91/cpuidle.c @@ -33,7 +33,7 @@ static struct cpuidle_driver at91_idle_driver = { /* Actual code that puts the SoC in different idle states */ static int at91_enter_idle(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { struct timeval before, after; int idle_time; @@ -41,10 +41,10 @@ static int at91_enter_idle(struct cpuidle_device *dev, local_irq_disable(); do_gettimeofday(&before); - if (state == &dev->states[0]) + if (index == 0) /* Wait for interrupt state */ cpu_do_idle(); - else if (state == &dev->states[1]) { + else if (index == 1) { asm("b 1f; .align 5; 1:"); asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ saved_lpr = sdram_selfrefresh_enable(); @@ -55,7 +55,9 @@ static int at91_enter_idle(struct cpuidle_device *dev, local_irq_enable(); idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + (after.tv_usec - before.tv_usec); - return idle_time; + + dev->last_residency = idle_time; + return index; } /* Initialize CPU idle by registering the idle states */ diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index bd59f31b8a95..ca8582a95ad9 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -78,9 +78,9 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = { /* Actual code that puts the SoC in different idle states */ static int davinci_enter_idle(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { - struct davinci_ops *ops = cpuidle_get_statedata(state); + struct davinci_ops *ops = cpuidle_get_statedata(&dev->states[index]); struct timeval before, after; int idle_time; @@ -98,7 +98,10 @@ static int davinci_enter_idle(struct cpuidle_device *dev, local_irq_enable(); idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + (after.tv_usec - before.tv_usec); - return idle_time; + + dev->last_residency = idle_time; + + return index; } static int __init davinci_cpuidle_probe(struct platform_device *pdev) diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c index bf7e96f2793a..ea026e72b977 100644 --- a/arch/arm/mach-exynos4/cpuidle.c +++ b/arch/arm/mach-exynos4/cpuidle.c @@ -16,7 +16,7 @@ #include static int exynos4_enter_idle(struct cpuidle_device *dev, - struct cpuidle_state *state); + int index); static struct cpuidle_state exynos4_cpuidle_set[] = { [0] = { @@ -37,7 +37,7 @@ static struct cpuidle_driver exynos4_idle_driver = { }; static int exynos4_enter_idle(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { struct timeval before, after; int idle_time; @@ -52,7 +52,8 @@ static int exynos4_enter_idle(struct cpuidle_device *dev, idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + (after.tv_usec - before.tv_usec); - return idle_time; + dev->last_residency = idle_time; + return index; } static int __init exynos4_init_cpuidle(void) diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c index f68d33f1f396..358dd80b3a07 100644 --- a/arch/arm/mach-kirkwood/cpuidle.c +++ b/arch/arm/mach-kirkwood/cpuidle.c @@ -32,17 +32,17 @@ static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); /* Actual code that puts the SoC in different idle states */ static int kirkwood_enter_idle(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { struct timeval before, after; int idle_time; local_irq_disable(); do_gettimeofday(&before); - if (state == &dev->states[0]) + if (index == 0) /* Wait for interrupt state */ cpu_do_idle(); - else if (state == &dev->states[1]) { + else if (index == 1) { /* * Following write will put DDR in self refresh. * Note that we have 256 cycles before DDR puts it @@ -57,7 +57,11 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev, local_irq_enable(); idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + (after.tv_usec - before.tv_usec); - return idle_time; + + /* Update last residency */ + dev->last_residency = idle_time; + + return index; } /* Initialize CPU idle by registering the idle states */ diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 4bf6e6e8b100..58425c75f1b8 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -88,17 +88,19 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device - * @state: The target state to be programmed + * @index: the index of state to be entered * * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ static int omap3_enter_idle(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { - struct omap3_idle_statedata *cx = cpuidle_get_statedata(state); + struct omap3_idle_statedata *cx = + cpuidle_get_statedata(&dev->states[index]); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; + int idle_time; /* Used to keep track of the total time in idle */ getnstimeofday(&ts_preidle); @@ -113,7 +115,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, goto return_sleep_time; /* Deny idle for C1 */ - if (state == &dev->states[0]) { + if (index == 0) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); } @@ -122,7 +124,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, omap_sram_idle(); /* Re-allow idle for C1 */ - if (state == &dev->states[0]) { + if (index == 0) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); } @@ -134,28 +136,35 @@ static int omap3_enter_idle(struct cpuidle_device *dev, local_irq_enable(); local_fiq_enable(); - return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; + idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \ + USEC_PER_SEC; + + /* Update cpuidle counters */ + dev->last_residency = idle_time; + + return index; } /** * next_valid_state - Find next valid C-state * @dev: cpuidle device - * @state: Currently selected C-state + * @index: Index of currently selected c-state * - * If the current state is valid, it is returned back to the caller. - * Else, this function searches for a lower c-state which is still - * valid. + * If the state corresponding to index is valid, index is returned back + * to the caller. Else, this function searches for a lower c-state which is + * still valid (as defined in omap3_power_states[]) and returns its index. * * A state is valid if the 'valid' field is enabled and * if it satisfies the enable_off_mode condition. */ -static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, - struct cpuidle_state *curr) +static int next_valid_state(struct cpuidle_device *dev, + int index) { - struct cpuidle_state *next = NULL; + struct cpuidle_state *curr = &dev->states[index]; struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr); u32 mpu_deepest_state = PWRDM_POWER_RET; u32 core_deepest_state = PWRDM_POWER_RET; + int next_index = -1; if (enable_off_mode) { mpu_deepest_state = PWRDM_POWER_OFF; @@ -172,20 +181,20 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, if ((cx->valid) && (cx->mpu_state >= mpu_deepest_state) && (cx->core_state >= core_deepest_state)) { - return curr; + return index; } else { int idx = OMAP3_NUM_STATES - 1; /* Reach the current state starting at highest C-state */ for (; idx >= 0; idx--) { if (&dev->states[idx] == curr) { - next = &dev->states[idx]; + next_index = idx; break; } } /* Should never hit this condition */ - WARN_ON(next == NULL); + WARN_ON(next_index == -1); /* * Drop to next valid state. @@ -197,37 +206,39 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, if ((cx->valid) && (cx->mpu_state >= mpu_deepest_state) && (cx->core_state >= core_deepest_state)) { - next = &dev->states[idx]; + next_index = idx; break; } } /* * C1 is always valid. - * So, no need to check for 'next==NULL' outside this loop. + * So, no need to check for 'next_index == -1' outside + * this loop. */ } - return next; + return next_index; } /** * omap3_enter_idle_bm - Checks for any bus activity * @dev: cpuidle device - * @state: The target state to be programmed + * @index: array index of target state to be programmed * * This function checks for any pending activity and then programs * the device to the specified or a safer state. */ static int omap3_enter_idle_bm(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { - struct cpuidle_state *new_state; + struct cpuidle_state *state = &dev->states[index]; + int new_state_idx; u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; struct omap3_idle_statedata *cx; int ret; if (!omap3_can_sleep()) { - new_state = dev->safe_state; + new_state_idx = dev->safe_state_index; goto select_state; } @@ -237,7 +248,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, */ cam_state = pwrdm_read_pwrst(cam_pd); if (cam_state == PWRDM_POWER_ON) { - new_state = dev->safe_state; + new_state_idx = dev->safe_state_index; goto select_state; } @@ -264,11 +275,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_next_state); - new_state = next_valid_state(dev, state); + new_state_idx = next_valid_state(dev, index); select_state: - dev->last_state = new_state; - ret = omap3_enter_idle(dev, new_state); + ret = omap3_enter_idle(dev, new_state_idx); /* Restore original PER state if it was modified */ if (per_next_state != per_saved_state) @@ -339,11 +349,12 @@ int __init omap3_idle_init(void) cpuidle_register_driver(&omap3_idle_driver); dev = &per_cpu(omap3_idle_dev, smp_processor_id()); + dev->safe_state_index = -1; /* C1 . MPU WFI + Core active */ cx = _fill_cstate(dev, 0, "MPU ON + CORE ON"); (&dev->states[0])->enter = omap3_enter_idle; - dev->safe_state = &dev->states[0]; + dev->safe_state_index = 0; cx->valid = 1; /* C1 is always valid */ cx->mpu_state = PWRDM_POWER_ON; cx->core_state = PWRDM_POWER_ON; diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index e4469e7233cb..7be50d4c4268 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -25,11 +25,11 @@ static unsigned long cpuidle_mode[] = { }; static int cpuidle_sleep_enter(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { unsigned long allowed_mode = arch_hwblk_sleep_mode(); ktime_t before, after; - int requested_state = state - &dev->states[0]; + int requested_state = index; int allowed_state; int k; @@ -46,11 +46,13 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev, */ k = min_t(int, allowed_state, requested_state); - dev->last_state = &dev->states[k]; before = ktime_get(); sh_mobile_call_standby(cpuidle_mode[k]); after = ktime_get(); - return ktime_to_ns(ktime_sub(after, before)) >> 10; + + dev->last_residency = (int)ktime_to_ns(ktime_sub(after, before)) >> 10; + + return k; } static struct cpuidle_device cpuidle_dev; @@ -84,7 +86,7 @@ void sh_mobile_setup_cpuidle(void) state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = cpuidle_sleep_enter; - dev->safe_state = state; + dev->safe_state_index = i-1; if (sh_mobile_sleep_supported & SUSP_SH_SF) { state = &dev->states[i++]; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 431ab11c8c1b..9cd08cecb347 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -741,22 +741,24 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) /** * acpi_idle_enter_c1 - enters an ACPI C1 state-type * @dev: the target CPU - * @state: the state data + * @index: index of target state * * This is equivalent to the HALT instruction. */ static int acpi_idle_enter_c1(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { ktime_t kt1, kt2; s64 idle_time; struct acpi_processor *pr; + struct cpuidle_state *state = &dev->states[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state); pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; + return -EINVAL; local_irq_disable(); @@ -764,7 +766,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, if (acpi_idle_suspend) { local_irq_enable(); cpu_relax(); - return 0; + return -EINVAL; } lapic_timer_state_broadcast(pr, cx, 1); @@ -773,37 +775,46 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, kt2 = ktime_get_real(); idle_time = ktime_to_us(ktime_sub(kt2, kt1)); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + local_irq_enable(); cx->usage++; lapic_timer_state_broadcast(pr, cx, 0); - return idle_time; + return index; } /** * acpi_idle_enter_simple - enters an ACPI state without BM handling * @dev: the target CPU - * @state: the state data + * @index: the index of suggested state */ static int acpi_idle_enter_simple(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { struct acpi_processor *pr; + struct cpuidle_state *state = &dev->states[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state); ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; - - if (acpi_idle_suspend) - return(acpi_idle_enter_c1(dev, state)); + return -EINVAL; local_irq_disable(); + if (acpi_idle_suspend) { + local_irq_enable(); + cpu_relax(); + return -EINVAL; + } + + if (cx->entry_method != ACPI_CSTATE_FFH) { current_thread_info()->status &= ~TS_POLLING; /* @@ -815,7 +826,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; local_irq_enable(); - return 0; + return -EINVAL; } } @@ -837,6 +848,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -848,7 +862,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, lapic_timer_state_broadcast(pr, cx, 0); cx->time += idle_time; - return idle_time; + return index; } static int c3_cpu_count; @@ -857,14 +871,15 @@ static DEFINE_SPINLOCK(c3_lock); /** * acpi_idle_enter_bm - enters C3 with proper BM handling * @dev: the target CPU - * @state: the state data + * @index: the index of suggested state * * If BM is detected, the deepest non-C3 idle state is entered instead. */ static int acpi_idle_enter_bm(struct cpuidle_device *dev, - struct cpuidle_state *state) + int index) { struct acpi_processor *pr; + struct cpuidle_state *state = &dev->states[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state); ktime_t kt1, kt2; s64 idle_time_ns; @@ -872,22 +887,26 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; + return -EINVAL; - if (acpi_idle_suspend) - return(acpi_idle_enter_c1(dev, state)); + + if (acpi_idle_suspend) { + cpu_relax(); + return -EINVAL; + } if (!cx->bm_sts_skip && acpi_idle_bm_check()) { - if (dev->safe_state) { - dev->last_state = dev->safe_state; - return dev->safe_state->enter(dev, dev->safe_state); + if (dev->safe_state_index >= 0) { + return dev->states[dev->safe_state_index].enter(dev, + dev->safe_state_index); } else { local_irq_disable(); acpi_safe_halt(); local_irq_enable(); - return 0; + return -EINVAL; } } @@ -904,7 +923,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; local_irq_enable(); - return 0; + return -EINVAL; } } @@ -954,6 +973,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -965,7 +987,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, lapic_timer_state_broadcast(pr, cx, 0); cx->time += idle_time; - return idle_time; + return index; } struct cpuidle_driver acpi_idle_driver = { @@ -992,6 +1014,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) } dev->cpu = pr->id; + dev->safe_state_index = -1; for (i = 0; i < CPUIDLE_STATE_MAX; i++) { dev->states[i].name[0] = '\0'; dev->states[i].desc[0] = '\0'; @@ -1027,13 +1050,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_c1; - dev->safe_state = state; + dev->safe_state_index = count; break; case ACPI_STATE_C2: state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_simple; - dev->safe_state = state; + dev->safe_state_index = count; break; case ACPI_STATE_C3: diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index d4c542372886..88bd12104396 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -62,7 +62,7 @@ int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_state *target_state; - int next_state; + int next_state, entered_state; if (off) return -ENODEV; @@ -102,26 +102,27 @@ int cpuidle_idle_call(void) target_state = &dev->states[next_state]; - /* enter the state and update stats */ - dev->last_state = target_state; - trace_power_start(POWER_CSTATE, next_state, dev->cpu); trace_cpu_idle(next_state, dev->cpu); - dev->last_residency = target_state->enter(dev, target_state); + entered_state = target_state->enter(dev, next_state); trace_power_end(dev->cpu); trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); - if (dev->last_state) - target_state = dev->last_state; - - target_state->time += (unsigned long long)dev->last_residency; - target_state->usage++; + if (entered_state >= 0) { + /* Update cpuidle counters */ + /* This can be moved to within driver enter routine + * but that results in multiple copies of same code. + */ + dev->states[entered_state].time += + (unsigned long long)dev->last_residency; + dev->states[entered_state].usage++; + } /* give the governor an opportunity to reflect on the outcome */ if (cpuidle_curr_governor->reflect) - cpuidle_curr_governor->reflect(dev); + cpuidle_curr_governor->reflect(dev, entered_state); return 0; } @@ -172,11 +173,10 @@ void cpuidle_resume_and_unlock(void) EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); #ifdef CONFIG_ARCH_HAS_CPU_RELAX -static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) +static int poll_idle(struct cpuidle_device *dev, int index) { ktime_t t1, t2; s64 diff; - int ret; t1 = ktime_get(); local_irq_enable(); @@ -188,8 +188,9 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) if (diff > INT_MAX) diff = INT_MAX; - ret = (int) diff; - return ret; + dev->last_residency = (int) diff; + + return index; } static void poll_idle_init(struct cpuidle_device *dev) @@ -248,7 +249,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) dev->states[i].time = 0; } dev->last_residency = 0; - dev->last_state = NULL; smp_wmb(); diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 12c98900dcf8..6a686a76711f 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -153,11 +153,24 @@ static int ladder_enable_device(struct cpuidle_device *dev) return 0; } +/** + * ladder_reflect - update the correct last_state_idx + * @dev: the CPU + * @index: the index of actual state entered + */ +static void ladder_reflect(struct cpuidle_device *dev, int index) +{ + struct ladder_device *ldev = &__get_cpu_var(ladder_devices); + if (index > 0) + ldev->last_state_idx = index; +} + static struct cpuidle_governor ladder_governor = { .name = "ladder", .rating = 10, .enable = ladder_enable_device, .select = ladder_select_state, + .reflect = ladder_reflect, .owner = THIS_MODULE, }; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index c47f3d09c1ee..e4b200c5b441 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -310,14 +310,17 @@ static int menu_select(struct cpuidle_device *dev) /** * menu_reflect - records that data structures need update * @dev: the CPU + * @index: the index of actual entered state * * NOTE: it's important to be fast here because this operation will add to * the overall exit latency. */ -static void menu_reflect(struct cpuidle_device *dev) +static void menu_reflect(struct cpuidle_device *dev, int index) { struct menu_device *data = &__get_cpu_var(menu_devices); - data->needs_update = 1; + data->last_state_idx = index; + if (index >= 0) + data->needs_update = 1; } /** diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index a46dddf61078..a1c888d2216a 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -81,7 +81,7 @@ static unsigned int mwait_substates; static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; -static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); +static int intel_idle(struct cpuidle_device *dev, int index); static struct cpuidle_state *cpuidle_state_table; @@ -209,12 +209,13 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { /** * intel_idle * @dev: cpuidle_device - * @state: cpuidle state + * @index: index of cpuidle state * */ -static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) +static int intel_idle(struct cpuidle_device *dev, int index) { unsigned long ecx = 1; /* break on interrupt flag */ + struct cpuidle_state *state = &dev->states[index]; unsigned long eax = (unsigned long)cpuidle_get_statedata(state); unsigned int cstate; ktime_t kt_before, kt_after; @@ -256,7 +257,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); - return usec_delta; + /* Update cpuidle counters */ + dev->last_residency = (int)usec_delta; + + return index; } static void __setup_broadcast_timer(void *arg) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index b51629e15cfc..8da811bcdbdb 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -42,7 +42,7 @@ struct cpuidle_state { unsigned long long time; /* in US */ int (*enter) (struct cpuidle_device *dev, - struct cpuidle_state *state); + int index); }; /* Idle State Flags */ @@ -87,13 +87,12 @@ struct cpuidle_device { int state_count; struct cpuidle_state states[CPUIDLE_STATE_MAX]; struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; - struct cpuidle_state *last_state; struct list_head device_list; struct kobject kobj; struct completion kobj_unregister; void *governor_data; - struct cpuidle_state *safe_state; + int safe_state_index; int (*prepare) (struct cpuidle_device *dev); }; @@ -169,7 +168,7 @@ struct cpuidle_governor { void (*disable) (struct cpuidle_device *dev); int (*select) (struct cpuidle_device *dev); - void (*reflect) (struct cpuidle_device *dev); + void (*reflect) (struct cpuidle_device *dev, int index); struct module *owner; }; From b25edc42bfb9602f0503474b2c94701d5536ce60 Mon Sep 17 00:00:00 2001 From: Deepthi Dharwar Date: Fri, 28 Oct 2011 16:20:24 +0530 Subject: [PATCH 1543/1596] cpuidle: Remove CPUIDLE_FLAG_IGNORE and dev->prepare() The cpuidle_device->prepare() mechanism causes updates to the cpuidle_state[].flags, setting and clearing CPUIDLE_FLAG_IGNORE to tell the governor not to chose a state on a per-cpu basis at run-time. State demotion is now handled by the driver and it returns the actual state entered. Hence, this mechanism is not required. Also this removes per-cpu flags from cpuidle_state enabling it to be made global. Reference: https://lkml.org/lkml/2011/3/25/52 Signed-off-by: Deepthi Dharwar Signed-off-by: Trinabh Gupta Tested-by: Jean Pihet Acked-by: Arjan van de Ven Reviewed-by: Kevin Hilman Signed-off-by: Len Brown --- drivers/cpuidle/cpuidle.c | 10 ---------- drivers/cpuidle/governors/menu.c | 2 -- include/linux/cpuidle.h | 3 --- 3 files changed, 15 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 88bd12104396..f66bcf9bfe93 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -83,16 +83,6 @@ int cpuidle_idle_call(void) hrtimer_peek_ahead_timers(); #endif - /* - * Call the device's prepare function before calling the - * governor's select function. ->prepare gives the device's - * cpuidle driver a chance to update any dynamic information - * of its cpuidle states for the current idle period, e.g. - * state availability, latencies, residencies, etc. - */ - if (dev->prepare) - dev->prepare(dev); - /* ask the governor for the next state */ next_state = cpuidle_curr_governor->select(dev); if (need_resched()) { diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index e4b200c5b441..af724e823c8e 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -288,8 +288,6 @@ static int menu_select(struct cpuidle_device *dev) for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { struct cpuidle_state *s = &dev->states[i]; - if (s->flags & CPUIDLE_FLAG_IGNORE) - continue; if (s->target_residency > data->predicted_us) continue; if (s->exit_latency > latency_req) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 8da811bcdbdb..c6d85cf90eb2 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -47,7 +47,6 @@ struct cpuidle_state { /* Idle State Flags */ #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ -#define CPUIDLE_FLAG_IGNORE (0x100) /* ignore during this idle period */ #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) @@ -93,8 +92,6 @@ struct cpuidle_device { struct completion kobj_unregister; void *governor_data; int safe_state_index; - - int (*prepare) (struct cpuidle_device *dev); }; DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); From 4202735e8ab6ecfb0381631a0d0b58fefe0bd4e2 Mon Sep 17 00:00:00 2001 From: Deepthi Dharwar Date: Fri, 28 Oct 2011 16:20:33 +0530 Subject: [PATCH 1544/1596] cpuidle: Split cpuidle_state structure and move per-cpu statistics fields This is the first step towards global registration of cpuidle states. The statistics used primarily by the governor are per-cpu and have to be split from rest of the fields inside cpuidle_state, which would be made global i.e. single copy. The driver_data field is also per-cpu and moved. Signed-off-by: Deepthi Dharwar Signed-off-by: Trinabh Gupta Tested-by: Jean Pihet Reviewed-by: Kevin Hilman Acked-by: Arjan van de Ven Acked-by: Kevin Hilman Signed-off-by: Len Brown --- arch/arm/mach-davinci/cpuidle.c | 5 ++-- arch/arm/mach-omap2/cpuidle34xx.c | 13 +++++---- drivers/acpi/processor_idle.c | 25 ++++++++--------- drivers/cpuidle/cpuidle.c | 11 ++++---- drivers/cpuidle/sysfs.c | 19 +++++++++---- drivers/idle/intel_idle.c | 46 +++++++++++++++++++++++-------- include/linux/cpuidle.h | 25 ++++++++++------- 7 files changed, 90 insertions(+), 54 deletions(-) diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index ca8582a95ad9..f2d2f34603d9 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -80,7 +80,8 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = { static int davinci_enter_idle(struct cpuidle_device *dev, int index) { - struct davinci_ops *ops = cpuidle_get_statedata(&dev->states[index]); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct davinci_ops *ops = cpuidle_get_statedata(state_usage); struct timeval before, after; int idle_time; @@ -142,7 +143,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) strcpy(device->states[1].desc, "WFI and DDR Self Refresh"); if (pdata->ddr2_pdown) davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN; - cpuidle_set_statedata(&device->states[1], &davinci_states[1]); + cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]); device->state_count = DAVINCI_CPUIDLE_MAX_STATES; diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 58425c75f1b8..d3fce7b97fcf 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -97,7 +97,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, int index) { struct omap3_idle_statedata *cx = - cpuidle_get_statedata(&dev->states[index]); + cpuidle_get_statedata(&dev->states_usage[index]); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; int idle_time; @@ -160,8 +160,9 @@ static int omap3_enter_idle(struct cpuidle_device *dev, static int next_valid_state(struct cpuidle_device *dev, int index) { + struct cpuidle_state_usage *curr_usage = &dev->states_usage[index]; struct cpuidle_state *curr = &dev->states[index]; - struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr); + struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage); u32 mpu_deepest_state = PWRDM_POWER_RET; u32 core_deepest_state = PWRDM_POWER_RET; int next_index = -1; @@ -202,7 +203,7 @@ static int next_valid_state(struct cpuidle_device *dev, */ idx--; for (; idx >= 0; idx--) { - cx = cpuidle_get_statedata(&dev->states[idx]); + cx = cpuidle_get_statedata(&dev->states_usage[idx]); if ((cx->valid) && (cx->mpu_state >= mpu_deepest_state) && (cx->core_state >= core_deepest_state)) { @@ -231,7 +232,6 @@ static int next_valid_state(struct cpuidle_device *dev, static int omap3_enter_idle_bm(struct cpuidle_device *dev, int index) { - struct cpuidle_state *state = &dev->states[index]; int new_state_idx; u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; struct omap3_idle_statedata *cx; @@ -264,7 +264,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, * Prevent PER off if CORE is not in retention or off as this * would disable PER wakeups completely. */ - cx = cpuidle_get_statedata(state); + cx = cpuidle_get_statedata(&dev->states_usage[index]); core_next_state = cx->core_state; per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); if ((per_next_state == PWRDM_POWER_OFF) && @@ -318,6 +318,7 @@ static inline struct omap3_idle_statedata *_fill_cstate( { struct omap3_idle_statedata *cx = &omap3_idle_data[idx]; struct cpuidle_state *state = &dev->states[idx]; + struct cpuidle_state_usage *state_usage = &dev->states_usage[idx]; state->exit_latency = cpuidle_params_table[idx].exit_latency; state->target_residency = cpuidle_params_table[idx].target_residency; @@ -326,7 +327,7 @@ static inline struct omap3_idle_statedata *_fill_cstate( cx->valid = cpuidle_params_table[idx].valid; sprintf(state->name, "C%d", idx + 1); strncpy(state->desc, descr, CPUIDLE_DESC_LEN); - cpuidle_set_statedata(state, cx); + cpuidle_set_statedata(state_usage, cx); return cx; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 9cd08cecb347..b98c75285690 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -745,14 +745,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) * * This is equivalent to the HALT instruction. */ -static int acpi_idle_enter_c1(struct cpuidle_device *dev, - int index) +static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index) { ktime_t kt1, kt2; s64 idle_time; struct acpi_processor *pr; - struct cpuidle_state *state = &dev->states[index]; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); pr = __this_cpu_read(processors); dev->last_residency = 0; @@ -790,12 +789,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, * @dev: the target CPU * @index: the index of suggested state */ -static int acpi_idle_enter_simple(struct cpuidle_device *dev, - int index) +static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index) { struct acpi_processor *pr; - struct cpuidle_state *state = &dev->states[index]; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; @@ -875,12 +873,11 @@ static DEFINE_SPINLOCK(c3_lock); * * If BM is detected, the deepest non-C3 idle state is entered instead. */ -static int acpi_idle_enter_bm(struct cpuidle_device *dev, - int index) +static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index) { struct acpi_processor *pr; - struct cpuidle_state *state = &dev->states[index]; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; @@ -1004,6 +1001,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) int i, count = CPUIDLE_DRIVER_STATE_START; struct acpi_processor_cx *cx; struct cpuidle_state *state; + struct cpuidle_state_usage *state_usage; struct cpuidle_device *dev = &pr->power.dev; if (!pr->flags.power_setup_done) @@ -1026,6 +1024,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { cx = &pr->power.states[i]; state = &dev->states[count]; + state_usage = &dev->states_usage[count]; if (!cx->valid) continue; @@ -1036,7 +1035,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) continue; #endif - cpuidle_set_statedata(state, cx); + cpuidle_set_statedata(state_usage, cx); snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index f66bcf9bfe93..7127e92fa8a1 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -105,9 +105,9 @@ int cpuidle_idle_call(void) /* This can be moved to within driver enter routine * but that results in multiple copies of same code. */ - dev->states[entered_state].time += + dev->states_usage[entered_state].time += (unsigned long long)dev->last_residency; - dev->states[entered_state].usage++; + dev->states_usage[entered_state].usage++; } /* give the governor an opportunity to reflect on the outcome */ @@ -186,8 +186,9 @@ static int poll_idle(struct cpuidle_device *dev, int index) static void poll_idle_init(struct cpuidle_device *dev) { struct cpuidle_state *state = &dev->states[0]; + struct cpuidle_state_usage *state_usage = &dev->states_usage[0]; - cpuidle_set_statedata(state, NULL); + cpuidle_set_statedata(state_usage, NULL); snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); @@ -235,8 +236,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev) goto fail_sysfs; for (i = 0; i < dev->state_count; i++) { - dev->states[i].usage = 0; - dev->states[i].time = 0; + dev->states_usage[i].usage = 0; + dev->states_usage[i].time = 0; } dev->last_residency = 0; diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index be7917ec40c9..8a1ace104476 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -216,7 +216,8 @@ static struct kobj_type ktype_cpuidle = { struct cpuidle_state_attr { struct attribute attr; - ssize_t (*show)(struct cpuidle_state *, char *); + ssize_t (*show)(struct cpuidle_state *, \ + struct cpuidle_state_usage *, char *); ssize_t (*store)(struct cpuidle_state *, const char *, size_t); }; @@ -224,19 +225,22 @@ struct cpuidle_state_attr { static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) #define define_show_state_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ return sprintf(buf, "%u\n", state->_name);\ } #define define_show_state_ull_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ - return sprintf(buf, "%llu\n", state->_name);\ + return sprintf(buf, "%llu\n", state_usage->_name);\ } #define define_show_state_str_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ if (state->_name[0] == '\0')\ return sprintf(buf, "\n");\ @@ -269,16 +273,18 @@ static struct attribute *cpuidle_state_default_attrs[] = { #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj) #define kobj_to_state(k) (kobj_to_state_obj(k)->state) +#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) static ssize_t cpuidle_state_show(struct kobject * kobj, struct attribute * attr ,char * buf) { int ret = -EIO; struct cpuidle_state *state = kobj_to_state(kobj); + struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj); struct cpuidle_state_attr * cattr = attr_to_stateattr(attr); if (cattr->show) - ret = cattr->show(state, buf); + ret = cattr->show(state, state_usage, buf); return ret; } @@ -323,6 +329,7 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) if (!kobj) goto error_state; kobj->state = &device->states[i]; + kobj->state_usage = &device->states_usage[i]; init_completion(&kobj->kobj_unregister); ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index a1c888d2216a..3aa8d4cb6dca 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -109,7 +109,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-NHM", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 3, .target_residency = 6, @@ -117,7 +116,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C3-NHM", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 20, .target_residency = 80, @@ -125,7 +123,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C3 */ .name = "C6-NHM", .desc = "MWAIT 0x20", - .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 200, .target_residency = 800, @@ -137,7 +134,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-SNB", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 1, .target_residency = 1, @@ -145,7 +141,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C3-SNB", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 80, .target_residency = 211, @@ -153,7 +148,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C3 */ .name = "C6-SNB", .desc = "MWAIT 0x20", - .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 104, .target_residency = 345, @@ -161,7 +155,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C4 */ .name = "C7-SNB", .desc = "MWAIT 0x30", - .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 109, .target_residency = 345, @@ -173,7 +166,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-ATM", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 1, .target_residency = 4, @@ -181,7 +173,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C2-ATM", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 20, .target_residency = 80, @@ -190,7 +181,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C4 */ .name = "C4-ATM", .desc = "MWAIT 0x30", - .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 100, .target_residency = 400, @@ -199,13 +189,41 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C6 */ .name = "C6-ATM", .desc = "MWAIT 0x52", - .driver_data = (void *) 0x52, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 140, .target_residency = 560, .enter = &intel_idle }, }; +static int get_driver_data(int cstate) +{ + int driver_data; + switch (cstate) { + + case 1: /* MWAIT C1 */ + driver_data = 0x00; + break; + case 2: /* MWAIT C2 */ + driver_data = 0x10; + break; + case 3: /* MWAIT C3 */ + driver_data = 0x20; + break; + case 4: /* MWAIT C4 */ + driver_data = 0x30; + break; + case 5: /* MWAIT C5 */ + driver_data = 0x40; + break; + case 6: /* MWAIT C6 */ + driver_data = 0x52; + break; + default: + driver_data = 0x00; + } + return driver_data; +} + /** * intel_idle * @dev: cpuidle_device @@ -216,7 +234,8 @@ static int intel_idle(struct cpuidle_device *dev, int index) { unsigned long ecx = 1; /* break on interrupt flag */ struct cpuidle_state *state = &dev->states[index]; - unsigned long eax = (unsigned long)cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); unsigned int cstate; ktime_t kt_before, kt_after; s64 usec_delta; @@ -451,6 +470,9 @@ static int intel_idle_cpuidle_devices_init(void) dev->states[dev->state_count] = /* structure copy */ cpuidle_state_table[cstate]; + dev->states_usage[dev->state_count].driver_data = + (void *)get_driver_data(cstate); + dev->state_count += 1; } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index c6d85cf90eb2..0156540b3f79 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -28,19 +28,22 @@ struct cpuidle_device; * CPUIDLE DEVICE INTERFACE * ****************************/ +struct cpuidle_state_usage { + void *driver_data; + + unsigned long long usage; + unsigned long long time; /* in US */ +}; + struct cpuidle_state { char name[CPUIDLE_NAME_LEN]; char desc[CPUIDLE_DESC_LEN]; - void *driver_data; unsigned int flags; unsigned int exit_latency; /* in US */ unsigned int power_usage; /* in mW */ unsigned int target_residency; /* in US */ - unsigned long long usage; - unsigned long long time; /* in US */ - int (*enter) (struct cpuidle_device *dev, int index); }; @@ -52,26 +55,27 @@ struct cpuidle_state { /** * cpuidle_get_statedata - retrieves private driver state data - * @state: the state + * @st_usage: the state usage statistics */ -static inline void * cpuidle_get_statedata(struct cpuidle_state *state) +static inline void *cpuidle_get_statedata(struct cpuidle_state_usage *st_usage) { - return state->driver_data; + return st_usage->driver_data; } /** * cpuidle_set_statedata - stores private driver state data - * @state: the state + * @st_usage: the state usage statistics * @data: the private data */ static inline void -cpuidle_set_statedata(struct cpuidle_state *state, void *data) +cpuidle_set_statedata(struct cpuidle_state_usage *st_usage, void *data) { - state->driver_data = data; + st_usage->driver_data = data; } struct cpuidle_state_kobj { struct cpuidle_state *state; + struct cpuidle_state_usage *state_usage; struct completion kobj_unregister; struct kobject kobj; }; @@ -85,6 +89,7 @@ struct cpuidle_device { int last_residency; int state_count; struct cpuidle_state states[CPUIDLE_STATE_MAX]; + struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; struct list_head device_list; From 46bcfad7a819bd17ac4e831b04405152d59784ab Mon Sep 17 00:00:00 2001 From: Deepthi Dharwar Date: Fri, 28 Oct 2011 16:20:42 +0530 Subject: [PATCH 1545/1596] cpuidle: Single/Global registration of idle states This patch makes the cpuidle_states structure global (single copy) instead of per-cpu. The statistics needed on per-cpu basis by the governor are kept per-cpu. This simplifies the cpuidle subsystem as state registration is done by single cpu only. Having single copy of cpuidle_states saves memory. Rare case of asymmetric C-states can be handled within the cpuidle driver and architectures such as POWER do not have asymmetric C-states. Having single/global registration of all the idle states, dynamic C-state transitions on x86 are handled by the boot cpu. Here, the boot cpu would disable all the devices, re-populate the states and later enable all the devices, irrespective of the cpu that would receive the notification first. Reference: https://lkml.org/lkml/2011/4/25/83 Signed-off-by: Deepthi Dharwar Signed-off-by: Trinabh Gupta Tested-by: Jean Pihet Reviewed-by: Kevin Hilman Acked-by: Arjan van de Ven Acked-by: Kevin Hilman Signed-off-by: Len Brown --- arch/arm/mach-at91/cpuidle.c | 31 +++-- arch/arm/mach-davinci/cpuidle.c | 39 +++--- arch/arm/mach-exynos4/cpuidle.c | 23 ++-- arch/arm/mach-kirkwood/cpuidle.c | 30 ++-- arch/arm/mach-omap2/cpuidle34xx.c | 73 ++++++---- arch/sh/kernel/cpu/shmobile/cpuidle.c | 18 ++- drivers/acpi/processor_driver.c | 20 +-- drivers/acpi/processor_idle.c | 191 ++++++++++++++++++++++---- drivers/cpuidle/cpuidle.c | 45 ++---- drivers/cpuidle/driver.c | 25 ++++ drivers/cpuidle/governors/ladder.c | 28 ++-- drivers/cpuidle/governors/menu.c | 20 +-- drivers/cpuidle/sysfs.c | 3 +- drivers/idle/intel_idle.c | 80 ++++++++--- include/acpi/processor.h | 1 + include/linux/cpuidle.h | 19 ++- 16 files changed, 439 insertions(+), 207 deletions(-) diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c index 4696a0d61e2e..93178f67420e 100644 --- a/arch/arm/mach-at91/cpuidle.c +++ b/arch/arm/mach-at91/cpuidle.c @@ -33,6 +33,7 @@ static struct cpuidle_driver at91_idle_driver = { /* Actual code that puts the SoC in different idle states */ static int at91_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct timeval before, after; @@ -64,27 +65,29 @@ static int at91_enter_idle(struct cpuidle_device *dev, static int at91_init_cpuidle(void) { struct cpuidle_device *device; - - cpuidle_register_driver(&at91_idle_driver); + struct cpuidle_driver *driver = &at91_idle_driver; device = &per_cpu(at91_cpuidle_device, smp_processor_id()); device->state_count = AT91_MAX_STATES; + driver->state_count = AT91_MAX_STATES; /* Wait for interrupt state */ - device->states[0].enter = at91_enter_idle; - device->states[0].exit_latency = 1; - device->states[0].target_residency = 10000; - device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(device->states[0].name, "WFI"); - strcpy(device->states[0].desc, "Wait for interrupt"); + driver->states[0].enter = at91_enter_idle; + driver->states[0].exit_latency = 1; + driver->states[0].target_residency = 10000; + driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(driver->states[0].name, "WFI"); + strcpy(driver->states[0].desc, "Wait for interrupt"); /* Wait for interrupt and RAM self refresh state */ - device->states[1].enter = at91_enter_idle; - device->states[1].exit_latency = 10; - device->states[1].target_residency = 10000; - device->states[1].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(device->states[1].name, "RAM_SR"); - strcpy(device->states[1].desc, "WFI and RAM Self Refresh"); + driver->states[1].enter = at91_enter_idle; + driver->states[1].exit_latency = 10; + driver->states[1].target_residency = 10000; + driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(driver->states[1].name, "RAM_SR"); + strcpy(driver->states[1].desc, "WFI and RAM Self Refresh"); + + cpuidle_register_driver(&at91_idle_driver); if (cpuidle_register_device(device)) { printk(KERN_ERR "at91_init_cpuidle: Failed registering\n"); diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index f2d2f34603d9..dbeeccd00173 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -78,6 +78,7 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = { /* Actual code that puts the SoC in different idle states */ static int davinci_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; @@ -109,6 +110,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) { int ret; struct cpuidle_device *device; + struct cpuidle_driver *driver = &davinci_idle_driver; struct davinci_cpuidle_config *pdata = pdev->dev.platform_data; device = &per_cpu(davinci_cpuidle_device, smp_processor_id()); @@ -120,32 +122,33 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) ddr2_reg_base = pdata->ddr2_ctlr_base; - ret = cpuidle_register_driver(&davinci_idle_driver); - if (ret) { - dev_err(&pdev->dev, "failed to register driver\n"); - return ret; - } - /* Wait for interrupt state */ - device->states[0].enter = davinci_enter_idle; - device->states[0].exit_latency = 1; - device->states[0].target_residency = 10000; - device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(device->states[0].name, "WFI"); - strcpy(device->states[0].desc, "Wait for interrupt"); + driver->states[0].enter = davinci_enter_idle; + driver->states[0].exit_latency = 1; + driver->states[0].target_residency = 10000; + driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(driver->states[0].name, "WFI"); + strcpy(driver->states[0].desc, "Wait for interrupt"); /* Wait for interrupt and DDR self refresh state */ - device->states[1].enter = davinci_enter_idle; - device->states[1].exit_latency = 10; - device->states[1].target_residency = 10000; - device->states[1].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(device->states[1].name, "DDR SR"); - strcpy(device->states[1].desc, "WFI and DDR Self Refresh"); + driver->states[1].enter = davinci_enter_idle; + driver->states[1].exit_latency = 10; + driver->states[1].target_residency = 10000; + driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(driver->states[1].name, "DDR SR"); + strcpy(driver->states[1].desc, "WFI and DDR Self Refresh"); if (pdata->ddr2_pdown) davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN; cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]); device->state_count = DAVINCI_CPUIDLE_MAX_STATES; + driver->state_count = DAVINCI_CPUIDLE_MAX_STATES; + + ret = cpuidle_register_driver(&davinci_idle_driver); + if (ret) { + dev_err(&pdev->dev, "failed to register driver\n"); + return ret; + } ret = cpuidle_register_device(device); if (ret) { diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c index ea026e72b977..35f6502144ae 100644 --- a/arch/arm/mach-exynos4/cpuidle.c +++ b/arch/arm/mach-exynos4/cpuidle.c @@ -16,6 +16,7 @@ #include static int exynos4_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index); static struct cpuidle_state exynos4_cpuidle_set[] = { @@ -37,6 +38,7 @@ static struct cpuidle_driver exynos4_idle_driver = { }; static int exynos4_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct timeval before, after; @@ -60,22 +62,23 @@ static int __init exynos4_init_cpuidle(void) { int i, max_cpuidle_state, cpu_id; struct cpuidle_device *device; - + struct cpuidle_driver *drv = &exynos4_idle_driver; + + /* Setup cpuidle driver */ + drv->state_count = (sizeof(exynos4_cpuidle_set) / + sizeof(struct cpuidle_state)); + max_cpuidle_state = drv->state_count; + for (i = 0; i < max_cpuidle_state; i++) { + memcpy(&drv->states[i], &exynos4_cpuidle_set[i], + sizeof(struct cpuidle_state)); + } cpuidle_register_driver(&exynos4_idle_driver); for_each_cpu(cpu_id, cpu_online_mask) { device = &per_cpu(exynos4_cpuidle_device, cpu_id); device->cpu = cpu_id; - device->state_count = (sizeof(exynos4_cpuidle_set) / - sizeof(struct cpuidle_state)); - - max_cpuidle_state = device->state_count; - - for (i = 0; i < max_cpuidle_state; i++) { - memcpy(&device->states[i], &exynos4_cpuidle_set[i], - sizeof(struct cpuidle_state)); - } + device->state_count = drv->state_count; if (cpuidle_register_device(device)) { printk(KERN_ERR "CPUidle register device failed\n,"); diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c index 358dd80b3a07..ffd690dc3d33 100644 --- a/arch/arm/mach-kirkwood/cpuidle.c +++ b/arch/arm/mach-kirkwood/cpuidle.c @@ -32,6 +32,7 @@ static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); /* Actual code that puts the SoC in different idle states */ static int kirkwood_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct timeval before, after; @@ -68,28 +69,29 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev, static int kirkwood_init_cpuidle(void) { struct cpuidle_device *device; - - cpuidle_register_driver(&kirkwood_idle_driver); + struct cpuidle_driver *driver = &kirkwood_idle_driver; device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); device->state_count = KIRKWOOD_MAX_STATES; + driver->state_count = KIRKWOOD_MAX_STATES; /* Wait for interrupt state */ - device->states[0].enter = kirkwood_enter_idle; - device->states[0].exit_latency = 1; - device->states[0].target_residency = 10000; - device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(device->states[0].name, "WFI"); - strcpy(device->states[0].desc, "Wait for interrupt"); + driver->states[0].enter = kirkwood_enter_idle; + driver->states[0].exit_latency = 1; + driver->states[0].target_residency = 10000; + driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(driver->states[0].name, "WFI"); + strcpy(driver->states[0].desc, "Wait for interrupt"); /* Wait for interrupt and DDR self refresh state */ - device->states[1].enter = kirkwood_enter_idle; - device->states[1].exit_latency = 10; - device->states[1].target_residency = 10000; - device->states[1].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(device->states[1].name, "DDR SR"); - strcpy(device->states[1].desc, "WFI and DDR Self Refresh"); + driver->states[1].enter = kirkwood_enter_idle; + driver->states[1].exit_latency = 10; + driver->states[1].target_residency = 10000; + driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(driver->states[1].name, "DDR SR"); + strcpy(driver->states[1].desc, "WFI and DDR Self Refresh"); + cpuidle_register_driver(&kirkwood_idle_driver); if (cpuidle_register_device(device)) { printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n"); return -EIO; diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index d3fce7b97fcf..1fe35c24fba2 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -88,12 +88,14 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device + * @drv: cpuidle driver * @index: the index of state to be entered * * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ static int omap3_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct omap3_idle_statedata *cx = @@ -148,6 +150,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, /** * next_valid_state - Find next valid C-state * @dev: cpuidle device + * @drv: cpuidle driver * @index: Index of currently selected c-state * * If the state corresponding to index is valid, index is returned back @@ -158,10 +161,11 @@ static int omap3_enter_idle(struct cpuidle_device *dev, * if it satisfies the enable_off_mode condition. */ static int next_valid_state(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct cpuidle_state_usage *curr_usage = &dev->states_usage[index]; - struct cpuidle_state *curr = &dev->states[index]; + struct cpuidle_state *curr = &drv->states[index]; struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage); u32 mpu_deepest_state = PWRDM_POWER_RET; u32 core_deepest_state = PWRDM_POWER_RET; @@ -188,7 +192,7 @@ static int next_valid_state(struct cpuidle_device *dev, /* Reach the current state starting at highest C-state */ for (; idx >= 0; idx--) { - if (&dev->states[idx] == curr) { + if (&drv->states[idx] == curr) { next_index = idx; break; } @@ -224,12 +228,14 @@ static int next_valid_state(struct cpuidle_device *dev, /** * omap3_enter_idle_bm - Checks for any bus activity * @dev: cpuidle device + * @drv: cpuidle driver * @index: array index of target state to be programmed * * This function checks for any pending activity and then programs * the device to the specified or a safer state. */ static int omap3_enter_idle_bm(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { int new_state_idx; @@ -238,7 +244,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, int ret; if (!omap3_can_sleep()) { - new_state_idx = dev->safe_state_index; + new_state_idx = drv->safe_state_index; goto select_state; } @@ -248,7 +254,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, */ cam_state = pwrdm_read_pwrst(cam_pd); if (cam_state == PWRDM_POWER_ON) { - new_state_idx = dev->safe_state_index; + new_state_idx = drv->safe_state_index; goto select_state; } @@ -275,10 +281,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_next_state); - new_state_idx = next_valid_state(dev, index); + new_state_idx = next_valid_state(dev, drv, index); select_state: - ret = omap3_enter_idle(dev, new_state_idx); + ret = omap3_enter_idle(dev, drv, new_state_idx); /* Restore original PER state if it was modified */ if (per_next_state != per_saved_state) @@ -311,22 +317,30 @@ struct cpuidle_driver omap3_idle_driver = { .owner = THIS_MODULE, }; -/* Helper to fill the C-state common data and register the driver_data */ -static inline struct omap3_idle_statedata *_fill_cstate( - struct cpuidle_device *dev, +/* Helper to fill the C-state common data*/ +static inline void _fill_cstate(struct cpuidle_driver *drv, int idx, const char *descr) { - struct omap3_idle_statedata *cx = &omap3_idle_data[idx]; - struct cpuidle_state *state = &dev->states[idx]; - struct cpuidle_state_usage *state_usage = &dev->states_usage[idx]; + struct cpuidle_state *state = &drv->states[idx]; state->exit_latency = cpuidle_params_table[idx].exit_latency; state->target_residency = cpuidle_params_table[idx].target_residency; state->flags = CPUIDLE_FLAG_TIME_VALID; state->enter = omap3_enter_idle_bm; - cx->valid = cpuidle_params_table[idx].valid; sprintf(state->name, "C%d", idx + 1); strncpy(state->desc, descr, CPUIDLE_DESC_LEN); + +} + +/* Helper to register the driver_data */ +static inline struct omap3_idle_statedata *_fill_cstate_usage( + struct cpuidle_device *dev, + int idx) +{ + struct omap3_idle_statedata *cx = &omap3_idle_data[idx]; + struct cpuidle_state_usage *state_usage = &dev->states_usage[idx]; + + cx->valid = cpuidle_params_table[idx].valid; cpuidle_set_statedata(state_usage, cx); return cx; @@ -341,6 +355,7 @@ static inline struct omap3_idle_statedata *_fill_cstate( int __init omap3_idle_init(void) { struct cpuidle_device *dev; + struct cpuidle_driver *drv = &omap3_idle_driver; struct omap3_idle_statedata *cx; mpu_pd = pwrdm_lookup("mpu_pwrdm"); @@ -348,45 +363,52 @@ int __init omap3_idle_init(void) per_pd = pwrdm_lookup("per_pwrdm"); cam_pd = pwrdm_lookup("cam_pwrdm"); - cpuidle_register_driver(&omap3_idle_driver); + + drv->safe_state_index = -1; dev = &per_cpu(omap3_idle_dev, smp_processor_id()); - dev->safe_state_index = -1; /* C1 . MPU WFI + Core active */ - cx = _fill_cstate(dev, 0, "MPU ON + CORE ON"); - (&dev->states[0])->enter = omap3_enter_idle; - dev->safe_state_index = 0; + _fill_cstate(drv, 0, "MPU ON + CORE ON"); + (&drv->states[0])->enter = omap3_enter_idle; + drv->safe_state_index = 0; + cx = _fill_cstate_usage(dev, 0); cx->valid = 1; /* C1 is always valid */ cx->mpu_state = PWRDM_POWER_ON; cx->core_state = PWRDM_POWER_ON; /* C2 . MPU WFI + Core inactive */ - cx = _fill_cstate(dev, 1, "MPU ON + CORE ON"); + _fill_cstate(drv, 1, "MPU ON + CORE ON"); + cx = _fill_cstate_usage(dev, 1); cx->mpu_state = PWRDM_POWER_ON; cx->core_state = PWRDM_POWER_ON; /* C3 . MPU CSWR + Core inactive */ - cx = _fill_cstate(dev, 2, "MPU RET + CORE ON"); + _fill_cstate(drv, 2, "MPU RET + CORE ON"); + cx = _fill_cstate_usage(dev, 2); cx->mpu_state = PWRDM_POWER_RET; cx->core_state = PWRDM_POWER_ON; /* C4 . MPU OFF + Core inactive */ - cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON"); + _fill_cstate(drv, 3, "MPU OFF + CORE ON"); + cx = _fill_cstate_usage(dev, 3); cx->mpu_state = PWRDM_POWER_OFF; cx->core_state = PWRDM_POWER_ON; /* C5 . MPU RET + Core RET */ - cx = _fill_cstate(dev, 4, "MPU RET + CORE RET"); + _fill_cstate(drv, 4, "MPU RET + CORE RET"); + cx = _fill_cstate_usage(dev, 4); cx->mpu_state = PWRDM_POWER_RET; cx->core_state = PWRDM_POWER_RET; /* C6 . MPU OFF + Core RET */ - cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET"); + _fill_cstate(drv, 5, "MPU OFF + CORE RET"); + cx = _fill_cstate_usage(dev, 5); cx->mpu_state = PWRDM_POWER_OFF; cx->core_state = PWRDM_POWER_RET; /* C7 . MPU OFF + Core OFF */ - cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF"); + _fill_cstate(drv, 6, "MPU OFF + CORE OFF"); + cx = _fill_cstate_usage(dev, 6); /* * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot * enable OFF mode in a stable form for previous revisions. @@ -400,6 +422,9 @@ int __init omap3_idle_init(void) cx->mpu_state = PWRDM_POWER_OFF; cx->core_state = PWRDM_POWER_OFF; + drv->state_count = OMAP3_NUM_STATES; + cpuidle_register_driver(&omap3_idle_driver); + dev->state_count = OMAP3_NUM_STATES; if (cpuidle_register_device(dev)) { printk(KERN_ERR "%s: CPUidle register device failed\n", diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 7be50d4c4268..ad1012ad6b42 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -25,6 +25,7 @@ static unsigned long cpuidle_mode[] = { }; static int cpuidle_sleep_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { unsigned long allowed_mode = arch_hwblk_sleep_mode(); @@ -64,19 +65,19 @@ static struct cpuidle_driver cpuidle_driver = { void sh_mobile_setup_cpuidle(void) { struct cpuidle_device *dev = &cpuidle_dev; + struct cpuidle_driver *drv = &cpuidle_driver; struct cpuidle_state *state; int i; - cpuidle_register_driver(&cpuidle_driver); for (i = 0; i < CPUIDLE_STATE_MAX; i++) { - dev->states[i].name[0] = '\0'; - dev->states[i].desc[0] = '\0'; + drv->states[i].name[0] = '\0'; + drv->states[i].desc[0] = '\0'; } i = CPUIDLE_DRIVER_STATE_START; - state = &dev->states[i++]; + state = &drv->states[i++]; snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN); state->exit_latency = 1; @@ -86,10 +87,10 @@ void sh_mobile_setup_cpuidle(void) state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = cpuidle_sleep_enter; - dev->safe_state_index = i-1; + drv->safe_state_index = i-1; if (sh_mobile_sleep_supported & SUSP_SH_SF) { - state = &dev->states[i++]; + state = &drv->states[i++]; snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN); @@ -102,7 +103,7 @@ void sh_mobile_setup_cpuidle(void) } if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) { - state = &dev->states[i++]; + state = &drv->states[i++]; snprintf(state->name, CPUIDLE_NAME_LEN, "C3"); strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", CPUIDLE_DESC_LEN); @@ -114,7 +115,10 @@ void sh_mobile_setup_cpuidle(void) state->enter = cpuidle_sleep_enter; } + drv->state_count = i; dev->state_count = i; + cpuidle_register_driver(&cpuidle_driver); + cpuidle_register_device(dev); } diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index a4e0f1ba6040..9d7bc9f6b6cc 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -426,7 +426,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, if (action == CPU_ONLINE && pr) { acpi_processor_ppc_has_changed(pr, 0); - acpi_processor_cst_has_changed(pr); + acpi_processor_hotplug(pr); acpi_processor_reevaluate_tstate(pr, action); acpi_processor_tstate_has_changed(pr); } @@ -503,8 +503,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); - - if (cpuidle_get_driver() == &acpi_idle_driver) + if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr, device); pr->cdev = thermal_cooling_device_register("Processor", device, @@ -800,17 +799,9 @@ static int __init acpi_processor_init(void) memset(&errata, 0, sizeof(errata)); - if (!cpuidle_register_driver(&acpi_idle_driver)) { - printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", - acpi_idle_driver.name); - } else { - printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n", - cpuidle_get_driver()->name); - } - result = acpi_bus_register_driver(&acpi_processor_driver); if (result < 0) - goto out_cpuidle; + return result; acpi_processor_install_hotplug_notify(); @@ -821,11 +812,6 @@ static int __init acpi_processor_init(void) acpi_processor_throttling_init(); return 0; - -out_cpuidle: - cpuidle_unregister_driver(&acpi_idle_driver); - - return result; } static void __exit acpi_processor_exit(void) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index b98c75285690..24fe3afa7119 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -741,11 +741,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) /** * acpi_idle_enter_c1 - enters an ACPI C1 state-type * @dev: the target CPU + * @drv: cpuidle driver containing cpuidle state info * @index: index of target state * * This is equivalent to the HALT instruction. */ -static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index) +static int acpi_idle_enter_c1(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { ktime_t kt1, kt2; s64 idle_time; @@ -787,9 +789,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index) /** * acpi_idle_enter_simple - enters an ACPI state without BM handling * @dev: the target CPU + * @drv: cpuidle driver with cpuidle state information * @index: the index of suggested state */ -static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index) +static int acpi_idle_enter_simple(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; @@ -869,11 +873,13 @@ static DEFINE_SPINLOCK(c3_lock); /** * acpi_idle_enter_bm - enters C3 with proper BM handling * @dev: the target CPU + * @drv: cpuidle driver containing state data * @index: the index of suggested state * * If BM is detected, the deepest non-C3 idle state is entered instead. */ -static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index) +static int acpi_idle_enter_bm(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; @@ -896,9 +902,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index) } if (!cx->bm_sts_skip && acpi_idle_bm_check()) { - if (dev->safe_state_index >= 0) { - return dev->states[dev->safe_state_index].enter(dev, - dev->safe_state_index); + if (drv->safe_state_index >= 0) { + return drv->states[drv->safe_state_index].enter(dev, + drv, drv->safe_state_index); } else { local_irq_disable(); acpi_safe_halt(); @@ -993,14 +999,15 @@ struct cpuidle_driver acpi_idle_driver = { }; /** - * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE + * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE + * device i.e. per-cpu data + * * @pr: the ACPI processor */ -static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) +static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr) { int i, count = CPUIDLE_DRIVER_STATE_START; struct acpi_processor_cx *cx; - struct cpuidle_state *state; struct cpuidle_state_usage *state_usage; struct cpuidle_device *dev = &pr->power.dev; @@ -1012,18 +1019,12 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) } dev->cpu = pr->id; - dev->safe_state_index = -1; - for (i = 0; i < CPUIDLE_STATE_MAX; i++) { - dev->states[i].name[0] = '\0'; - dev->states[i].desc[0] = '\0'; - } if (max_cstate == 0) max_cstate = 1; for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { cx = &pr->power.states[i]; - state = &dev->states[count]; state_usage = &dev->states_usage[count]; if (!cx->valid) @@ -1035,8 +1036,64 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) continue; #endif + cpuidle_set_statedata(state_usage, cx); + count++; + if (count == CPUIDLE_STATE_MAX) + break; + } + + dev->state_count = count; + + if (!count) + return -EINVAL; + + return 0; +} + +/** + * acpi_processor_setup_cpuidle states- prepares and configures cpuidle + * global state data i.e. idle routines + * + * @pr: the ACPI processor + */ +static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) +{ + int i, count = CPUIDLE_DRIVER_STATE_START; + struct acpi_processor_cx *cx; + struct cpuidle_state *state; + struct cpuidle_driver *drv = &acpi_idle_driver; + + if (!pr->flags.power_setup_done) + return -EINVAL; + + if (pr->flags.power == 0) + return -EINVAL; + + drv->safe_state_index = -1; + for (i = 0; i < CPUIDLE_STATE_MAX; i++) { + drv->states[i].name[0] = '\0'; + drv->states[i].desc[0] = '\0'; + } + + if (max_cstate == 0) + max_cstate = 1; + + for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { + cx = &pr->power.states[i]; + + if (!cx->valid) + continue; + +#ifdef CONFIG_HOTPLUG_CPU + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + continue; +#endif + + state = &drv->states[count]; snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); state->exit_latency = cx->latency; @@ -1049,13 +1106,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_c1; - dev->safe_state_index = count; + drv->safe_state_index = count; break; case ACPI_STATE_C2: state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_simple; - dev->safe_state_index = count; + drv->safe_state_index = count; break; case ACPI_STATE_C3: @@ -1071,7 +1128,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) break; } - dev->state_count = count; + drv->state_count = count; if (!count) return -EINVAL; @@ -1079,7 +1136,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) return 0; } -int acpi_processor_cst_has_changed(struct acpi_processor *pr) +int acpi_processor_hotplug(struct acpi_processor *pr) { int ret = 0; @@ -1100,7 +1157,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) cpuidle_disable_device(&pr->power.dev); acpi_processor_get_power_info(pr); if (pr->flags.power) { - acpi_processor_setup_cpuidle(pr); + acpi_processor_setup_cpuidle_cx(pr); ret = cpuidle_enable_device(&pr->power.dev); } cpuidle_resume_and_unlock(); @@ -1108,10 +1165,72 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) return ret; } +int acpi_processor_cst_has_changed(struct acpi_processor *pr) +{ + int cpu; + struct acpi_processor *_pr; + + if (disabled_by_idle_boot_param()) + return 0; + + if (!pr) + return -EINVAL; + + if (nocst) + return -ENODEV; + + if (!pr->flags.power_setup_done) + return -ENODEV; + + /* + * FIXME: Design the ACPI notification to make it once per + * system instead of once per-cpu. This condition is a hack + * to make the code that updates C-States be called once. + */ + + if (smp_processor_id() == 0 && + cpuidle_get_driver() == &acpi_idle_driver) { + + cpuidle_pause_and_lock(); + /* Protect against cpu-hotplug */ + get_online_cpus(); + + /* Disable all cpuidle devices */ + for_each_online_cpu(cpu) { + _pr = per_cpu(processors, cpu); + if (!_pr || !_pr->flags.power_setup_done) + continue; + cpuidle_disable_device(&_pr->power.dev); + } + + /* Populate Updated C-state information */ + acpi_processor_setup_cpuidle_states(pr); + + /* Enable all cpuidle devices */ + for_each_online_cpu(cpu) { + _pr = per_cpu(processors, cpu); + if (!_pr || !_pr->flags.power_setup_done) + continue; + acpi_processor_get_power_info(_pr); + if (_pr->flags.power) { + acpi_processor_setup_cpuidle_cx(_pr); + cpuidle_enable_device(&_pr->power.dev); + } + } + put_online_cpus(); + cpuidle_resume_and_unlock(); + } + + return 0; +} + +static int acpi_processor_registered; + int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { acpi_status status = 0; + int retval; static int first_run; if (disabled_by_idle_boot_param()) @@ -1148,9 +1267,26 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, * platforms that only support C1. */ if (pr->flags.power) { - acpi_processor_setup_cpuidle(pr); - if (cpuidle_register_device(&pr->power.dev)) - return -EIO; + /* Register acpi_idle_driver if not already registered */ + if (!acpi_processor_registered) { + acpi_processor_setup_cpuidle_states(pr); + retval = cpuidle_register_driver(&acpi_idle_driver); + if (retval) + return retval; + printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", + acpi_idle_driver.name); + } + /* Register per-cpu cpuidle_device. Cpuidle driver + * must already be registered before registering device + */ + acpi_processor_setup_cpuidle_cx(pr); + retval = cpuidle_register_device(&pr->power.dev); + if (retval) { + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); + return retval; + } + acpi_processor_registered++; } return 0; } @@ -1161,8 +1297,13 @@ int acpi_processor_power_exit(struct acpi_processor *pr, if (disabled_by_idle_boot_param()) return 0; - cpuidle_unregister_device(&pr->power.dev); - pr->flags.power_setup_done = 0; + if (pr->flags.power) { + cpuidle_unregister_device(&pr->power.dev); + acpi_processor_registered--; + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); + } + pr->flags.power_setup_done = 0; return 0; } diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 7127e92fa8a1..7a57b11eaa8d 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -61,6 +61,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); + struct cpuidle_driver *drv = cpuidle_get_driver(); struct cpuidle_state *target_state; int next_state, entered_state; @@ -84,18 +85,18 @@ int cpuidle_idle_call(void) #endif /* ask the governor for the next state */ - next_state = cpuidle_curr_governor->select(dev); + next_state = cpuidle_curr_governor->select(drv, dev); if (need_resched()) { local_irq_enable(); return 0; } - target_state = &dev->states[next_state]; + target_state = &drv->states[next_state]; trace_power_start(POWER_CSTATE, next_state, dev->cpu); trace_cpu_idle(next_state, dev->cpu); - entered_state = target_state->enter(dev, next_state); + entered_state = target_state->enter(dev, drv, next_state); trace_power_end(dev->cpu); trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); @@ -163,7 +164,8 @@ void cpuidle_resume_and_unlock(void) EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); #ifdef CONFIG_ARCH_HAS_CPU_RELAX -static int poll_idle(struct cpuidle_device *dev, int index) +static int poll_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { ktime_t t1, t2; s64 diff; @@ -183,12 +185,9 @@ static int poll_idle(struct cpuidle_device *dev, int index) return index; } -static void poll_idle_init(struct cpuidle_device *dev) +static void poll_idle_init(struct cpuidle_driver *drv) { - struct cpuidle_state *state = &dev->states[0]; - struct cpuidle_state_usage *state_usage = &dev->states_usage[0]; - - cpuidle_set_statedata(state_usage, NULL); + struct cpuidle_state *state = &drv->states[0]; snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); @@ -199,7 +198,7 @@ static void poll_idle_init(struct cpuidle_device *dev) state->enter = poll_idle; } #else -static void poll_idle_init(struct cpuidle_device *dev) {} +static void poll_idle_init(struct cpuidle_driver *drv) {} #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ /** @@ -226,13 +225,13 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return ret; } - poll_idle_init(dev); + poll_idle_init(cpuidle_get_driver()); if ((ret = cpuidle_add_state_sysfs(dev))) return ret; if (cpuidle_curr_governor->enable && - (ret = cpuidle_curr_governor->enable(dev))) + (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) goto fail_sysfs; for (i = 0; i < dev->state_count; i++) { @@ -273,7 +272,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev) dev->enabled = 0; if (cpuidle_curr_governor->disable) - cpuidle_curr_governor->disable(dev); + cpuidle_curr_governor->disable(cpuidle_get_driver(), dev); cpuidle_remove_state_sysfs(dev); enabled_devices--; @@ -301,26 +300,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) init_completion(&dev->kobj_unregister); - /* - * cpuidle driver should set the dev->power_specified bit - * before registering the device if the driver provides - * power_usage numbers. - * - * For those devices whose ->power_specified is not set, - * we fill in power_usage with decreasing values as the - * cpuidle code has an implicit assumption that state Cn - * uses less power than C(n-1). - * - * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned - * an power value of -1. So we use -2, -3, etc, for other - * c-states. - */ - if (!dev->power_specified) { - int i; - for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) - dev->states[i].power_usage = -1 - i; - } - per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); if ((ret = cpuidle_add_sysfs(sys_dev))) { diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 3f7e3cedd133..284d7af5a9c8 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -17,6 +17,30 @@ static struct cpuidle_driver *cpuidle_curr_driver; DEFINE_SPINLOCK(cpuidle_driver_lock); +static void __cpuidle_register_driver(struct cpuidle_driver *drv) +{ + int i; + /* + * cpuidle driver should set the drv->power_specified bit + * before registering if the driver provides + * power_usage numbers. + * + * If power_specified is not set, + * we fill in power_usage with decreasing values as the + * cpuidle code has an implicit assumption that state Cn + * uses less power than C(n-1). + * + * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned + * an power value of -1. So we use -2, -3, etc, for other + * c-states. + */ + if (!drv->power_specified) { + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) + drv->states[i].power_usage = -1 - i; + } +} + + /** * cpuidle_register_driver - registers a driver * @drv: the driver @@ -34,6 +58,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) spin_unlock(&cpuidle_driver_lock); return -EBUSY; } + __cpuidle_register_driver(drv); cpuidle_curr_driver = drv; spin_unlock(&cpuidle_driver_lock); diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 6a686a76711f..ef6b9e4727a7 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -60,9 +60,11 @@ static inline void ladder_do_selection(struct ladder_device *ldev, /** * ladder_select_state - selects the next state to enter + * @drv: cpuidle driver * @dev: the CPU */ -static int ladder_select_state(struct cpuidle_device *dev) +static int ladder_select_state(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { struct ladder_device *ldev = &__get_cpu_var(ladder_devices); struct ladder_device_state *last_state; @@ -77,15 +79,17 @@ static int ladder_select_state(struct cpuidle_device *dev) last_state = &ldev->states[last_idx]; - if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) - last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency; + if (drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) { + last_residency = cpuidle_get_last_residency(dev) - \ + drv->states[last_idx].exit_latency; + } else last_residency = last_state->threshold.promotion_time + 1; /* consider promotion */ - if (last_idx < dev->state_count - 1 && + if (last_idx < drv->state_count - 1 && last_residency > last_state->threshold.promotion_time && - dev->states[last_idx + 1].exit_latency <= latency_req) { + drv->states[last_idx + 1].exit_latency <= latency_req) { last_state->stats.promotion_count++; last_state->stats.demotion_count = 0; if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) { @@ -96,11 +100,11 @@ static int ladder_select_state(struct cpuidle_device *dev) /* consider demotion */ if (last_idx > CPUIDLE_DRIVER_STATE_START && - dev->states[last_idx].exit_latency > latency_req) { + drv->states[last_idx].exit_latency > latency_req) { int i; for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) { - if (dev->states[i].exit_latency <= latency_req) + if (drv->states[i].exit_latency <= latency_req) break; } ladder_do_selection(ldev, last_idx, i); @@ -123,9 +127,11 @@ static int ladder_select_state(struct cpuidle_device *dev) /** * ladder_enable_device - setup for the governor + * @drv: cpuidle driver * @dev: the CPU */ -static int ladder_enable_device(struct cpuidle_device *dev) +static int ladder_enable_device(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { int i; struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu); @@ -134,8 +140,8 @@ static int ladder_enable_device(struct cpuidle_device *dev) ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START; - for (i = 0; i < dev->state_count; i++) { - state = &dev->states[i]; + for (i = 0; i < drv->state_count; i++) { + state = &drv->states[i]; lstate = &ldev->states[i]; lstate->stats.promotion_count = 0; @@ -144,7 +150,7 @@ static int ladder_enable_device(struct cpuidle_device *dev) lstate->threshold.promotion_count = PROMOTION_COUNT; lstate->threshold.demotion_count = DEMOTION_COUNT; - if (i < dev->state_count - 1) + if (i < drv->state_count - 1) lstate->threshold.promotion_time = state->exit_latency; if (i > 0) lstate->threshold.demotion_time = state->exit_latency; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index af724e823c8e..bcbe88142135 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -182,7 +182,7 @@ static inline int performance_multiplier(void) static DEFINE_PER_CPU(struct menu_device, menu_devices); -static void menu_update(struct cpuidle_device *dev); +static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); /* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */ static u64 div_round64(u64 dividend, u32 divisor) @@ -228,9 +228,10 @@ static void detect_repeating_patterns(struct menu_device *data) /** * menu_select - selects the next idle state to enter + * @drv: cpuidle driver containing state data * @dev: the CPU */ -static int menu_select(struct cpuidle_device *dev) +static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); @@ -240,7 +241,7 @@ static int menu_select(struct cpuidle_device *dev) struct timespec t; if (data->needs_update) { - menu_update(dev); + menu_update(drv, dev); data->needs_update = 0; } @@ -285,8 +286,8 @@ static int menu_select(struct cpuidle_device *dev) * Find the idle state with the lowest power while satisfying * our constraints. */ - for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { - struct cpuidle_state *s = &dev->states[i]; + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; if (s->target_residency > data->predicted_us) continue; @@ -323,14 +324,15 @@ static void menu_reflect(struct cpuidle_device *dev, int index) /** * menu_update - attempts to guess what happened after entry + * @drv: cpuidle driver containing state data * @dev: the CPU */ -static void menu_update(struct cpuidle_device *dev) +static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int last_idx = data->last_state_idx; unsigned int last_idle_us = cpuidle_get_last_residency(dev); - struct cpuidle_state *target = &dev->states[last_idx]; + struct cpuidle_state *target = &drv->states[last_idx]; unsigned int measured_us; u64 new_factor; @@ -384,9 +386,11 @@ static void menu_update(struct cpuidle_device *dev) /** * menu_enable_device - scans a CPU's states and does setup + * @drv: cpuidle driver * @dev: the CPU */ -static int menu_enable_device(struct cpuidle_device *dev) +static int menu_enable_device(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { struct menu_device *data = &per_cpu(menu_devices, dev->cpu); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 8a1ace104476..1e756e160dca 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -322,13 +322,14 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) { int i, ret = -ENOMEM; struct cpuidle_state_kobj *kobj; + struct cpuidle_driver *drv = cpuidle_get_driver(); /* state statistics */ for (i = 0; i < device->state_count; i++) { kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); if (!kobj) goto error_state; - kobj->state = &device->states[i]; + kobj->state = &drv->states[i]; kobj->state_usage = &device->states_usage[i]; init_completion(&kobj->kobj_unregister); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 3aa8d4cb6dca..5be9d599ff6b 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -81,7 +81,8 @@ static unsigned int mwait_substates; static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; -static int intel_idle(struct cpuidle_device *dev, int index); +static int intel_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index); static struct cpuidle_state *cpuidle_state_table; @@ -227,13 +228,15 @@ static int get_driver_data(int cstate) /** * intel_idle * @dev: cpuidle_device + * @drv: cpuidle driver * @index: index of cpuidle state * */ -static int intel_idle(struct cpuidle_device *dev, int index) +static int intel_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { unsigned long ecx = 1; /* break on interrupt flag */ - struct cpuidle_state *state = &dev->states[index]; + struct cpuidle_state *state = &drv->states[index]; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); unsigned int cstate; @@ -419,6 +422,60 @@ static void intel_idle_cpuidle_devices_uninit(void) free_percpu(intel_idle_cpuidle_devices); return; } +/* + * intel_idle_cpuidle_driver_init() + * allocate, initialize cpuidle_states + */ +static int intel_idle_cpuidle_driver_init(void) +{ + int cstate; + struct cpuidle_driver *drv = &intel_idle_driver; + + drv->state_count = 1; + + for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { + int num_substates; + + if (cstate > max_cstate) { + printk(PREFIX "max_cstate %d reached\n", + max_cstate); + break; + } + + /* does the state exist in CPUID.MWAIT? */ + num_substates = (mwait_substates >> ((cstate) * 4)) + & MWAIT_SUBSTATE_MASK; + if (num_substates == 0) + continue; + /* is the state not enabled? */ + if (cpuidle_state_table[cstate].enter == NULL) { + /* does the driver not know about the state? */ + if (*cpuidle_state_table[cstate].name == '\0') + pr_debug(PREFIX "unaware of model 0x%x" + " MWAIT %d please" + " contact lenb@kernel.org", + boot_cpu_data.x86_model, cstate); + continue; + } + + if ((cstate > 2) && + !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) + mark_tsc_unstable("TSC halts in idle" + " states deeper than C2"); + + drv->states[drv->state_count] = /* structure copy */ + cpuidle_state_table[cstate]; + + drv->state_count += 1; + } + + if (auto_demotion_disable_flags) + smp_call_function(auto_demotion_disable, NULL, 1); + + return 0; +} + + /* * intel_idle_cpuidle_devices_init() * allocate, initialize, register cpuidle_devices @@ -453,23 +510,9 @@ static int intel_idle_cpuidle_devices_init(void) continue; /* is the state not enabled? */ if (cpuidle_state_table[cstate].enter == NULL) { - /* does the driver not know about the state? */ - if (*cpuidle_state_table[cstate].name == '\0') - pr_debug(PREFIX "unaware of model 0x%x" - " MWAIT %d please" - " contact lenb@kernel.org", - boot_cpu_data.x86_model, cstate); continue; } - if ((cstate > 2) && - !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) - mark_tsc_unstable("TSC halts in idle" - " states deeper than C2"); - - dev->states[dev->state_count] = /* structure copy */ - cpuidle_state_table[cstate]; - dev->states_usage[dev->state_count].driver_data = (void *)get_driver_data(cstate); @@ -484,8 +527,6 @@ static int intel_idle_cpuidle_devices_init(void) return -EIO; } } - if (auto_demotion_disable_flags) - smp_call_function(auto_demotion_disable, NULL, 1); return 0; } @@ -503,6 +544,7 @@ static int __init intel_idle_init(void) if (retval) return retval; + intel_idle_cpuidle_driver_init(); retval = cpuidle_register_driver(&intel_idle_driver); if (retval) { printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 67055f180330..610f6fb1bbc2 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -329,6 +329,7 @@ extern void acpi_processor_throttling_init(void); int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device); int acpi_processor_cst_has_changed(struct acpi_processor *pr); +int acpi_processor_hotplug(struct acpi_processor *pr); int acpi_processor_power_exit(struct acpi_processor *pr, struct acpi_device *device); int acpi_processor_suspend(struct acpi_device * device, pm_message_t state); diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 0156540b3f79..c90418822f40 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -22,6 +22,7 @@ #define CPUIDLE_DESC_LEN 32 struct cpuidle_device; +struct cpuidle_driver; /**************************** @@ -45,6 +46,7 @@ struct cpuidle_state { unsigned int target_residency; /* in US */ int (*enter) (struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index); }; @@ -83,12 +85,10 @@ struct cpuidle_state_kobj { struct cpuidle_device { unsigned int registered:1; unsigned int enabled:1; - unsigned int power_specified:1; unsigned int cpu; int last_residency; int state_count; - struct cpuidle_state states[CPUIDLE_STATE_MAX]; struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; @@ -96,7 +96,6 @@ struct cpuidle_device { struct kobject kobj; struct completion kobj_unregister; void *governor_data; - int safe_state_index; }; DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); @@ -120,6 +119,11 @@ static inline int cpuidle_get_last_residency(struct cpuidle_device *dev) struct cpuidle_driver { char name[CPUIDLE_NAME_LEN]; struct module *owner; + + unsigned int power_specified:1; + struct cpuidle_state states[CPUIDLE_STATE_MAX]; + int state_count; + int safe_state_index; }; #ifdef CONFIG_CPU_IDLE @@ -166,10 +170,13 @@ struct cpuidle_governor { struct list_head governor_list; unsigned int rating; - int (*enable) (struct cpuidle_device *dev); - void (*disable) (struct cpuidle_device *dev); + int (*enable) (struct cpuidle_driver *drv, + struct cpuidle_device *dev); + void (*disable) (struct cpuidle_driver *drv, + struct cpuidle_device *dev); - int (*select) (struct cpuidle_device *dev); + int (*select) (struct cpuidle_driver *drv, + struct cpuidle_device *dev); void (*reflect) (struct cpuidle_device *dev, int index); struct module *owner; From 21404b772a1c65f7b935b8c0fddc388a949f4e31 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Nov 2011 18:34:03 -0800 Subject: [PATCH 1546/1596] hid/apple: modern macbook airs use the standard apple function key translations This removes the use of the special "macbookair_fn_keys" keyboard translation table for the MacBookAir4,x models (ie the 2011 refresh). They use the standard apple_fn_keys[] translation. Apparently only the old MacBook Air's need a different translation table. This mirrors the change that commit da617c7cb915 ("HID: consolidate MacbookAir 4,1 mappings") did for the WELLSPRING6A ones, but does it for the WELLSPRING6 model used on the MacBookAir4,2. Reported-and-tested-by: Dirk Hohndel Cc: Jiri Kosina Cc: Joshua V Dillon Cc: Chase Douglas Signed-off-by: Linus Torvalds --- drivers/hid/hid-apple.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 8cdb4b45b30a..299d23871122 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -183,9 +183,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) table = macbookair_fn_keys; - else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI && - hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) - table = macbookair_fn_keys; else if (hid->product < 0x21d || hid->product >= 0x300) table = powerbook_fn_keys; else From 0084e4751e63a71b30f315710f976f8bb0c2cc07 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 7 Nov 2011 17:12:28 +1100 Subject: [PATCH 1547/1596] powerpc: fix building hvc_opal.c Fix building following build error: drivers/tty/hvc/hvc_opal.c:244:12: error: 'THIS_MODULE' undeclared here (not in a function) Signed-off-by: Michael Neuling [ New file from powerpc tree not following the new rules from the module.h split, both of which were merged today. - Linus ] Signed-off-by: Linus Torvalds --- drivers/tty/hvc/hvc_opal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 7b38512d6c41..ced26c8ccd57 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include From 31555213f03bca37d2c02e10946296052f4ecfcd Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Nov 2011 22:22:16 -0800 Subject: [PATCH 1548/1596] Revert "hvc_console: display printk messages on console." This reverts commit 361162459f62dc0826b82c9690a741a940f457f0. It causes an infinite loop when booting Linux under Xen, as so: [ 2.382984] console [hvc0] enabled [ 2.382984] console [hvc0] enabled [ 2.382984] console [hvc0] enabled ... as reported by Konrad Rzeszutek Wilk. And Rusty reports the same for lguest. He goes on to say: "This is not a concurrency problem: the issue seems to be that calling register_console() twice on the same struct console is a bad idea." and Greg says he'll fix it up properly at some point later. Revert for now. Reported-by: Konrad Rzeszutek Wilk Reported-by: Rusty Russell Requested-by: Stephen Rothwell Cc: Miche Baker-Harvey Cc: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/tty/hvc/hvc_console.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 7430bc3c8d53..b6b2d18fa38d 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -852,7 +852,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, * find index to use: * see if this vterm id matches one registered for console. */ - for (i = 0; i < MAX_NR_HVC_CONSOLES; i++) + for (i=0; i < MAX_NR_HVC_CONSOLES; i++) if (vtermnos[i] == hp->vtermno && cons_ops[i] == hp->ops) break; @@ -862,13 +862,9 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, i = ++last_hvc; hp->index = i; - hvc_console.index = i; - vtermnos[i] = vtermno; - cons_ops[i] = ops; list_add_tail(&(hp->next), &hvc_structs); spin_unlock(&hvc_structs_lock); - register_console(&hvc_console); return hp; } @@ -879,7 +875,6 @@ int hvc_remove(struct hvc_struct *hp) unsigned long flags; struct tty_struct *tty; - unregister_console(&hvc_console); spin_lock_irqsave(&hp->lock, flags); tty = tty_kref_get(hp->tty); From 3a73dbbc9bb3fc8594cd67af4db6c563175dfddb Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 7 Nov 2011 19:19:28 +0800 Subject: [PATCH 1549/1596] writeback: fix uninitialized task_ratelimit In balance_dirty_pages() task_ratelimit may be not initialized (initialization skiped by goto pause), and then used when calling tracing hook. Fix it by moving the task_ratelimit assignment before goto pause. Reported-by: Witold Baryluk Signed-off-by: Wu Fengguang --- mm/page-writeback.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 0360d1b5a1dd..a3278f005230 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1097,13 +1097,13 @@ static void balance_dirty_pages(struct address_space *mapping, pos_ratio = bdi_position_ratio(bdi, dirty_thresh, background_thresh, nr_dirty, bdi_thresh, bdi_dirty); - if (unlikely(pos_ratio == 0)) { + task_ratelimit = ((u64)dirty_ratelimit * pos_ratio) >> + RATELIMIT_CALC_SHIFT; + if (unlikely(task_ratelimit == 0)) { pause = max_pause; goto pause; } - task_ratelimit = (u64)dirty_ratelimit * - pos_ratio >> RATELIMIT_CALC_SHIFT; - pause = (HZ * pages_dirtied) / (task_ratelimit | 1); + pause = HZ * pages_dirtied / task_ratelimit; if (unlikely(pause <= 0)) { trace_balance_dirty_pages(bdi, dirty_thresh, From d4528b846ec8ba7ccf3116f1c2157c5e14ba46f3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 2 Nov 2011 09:43:08 +0100 Subject: [PATCH 1550/1596] vmwgfx: Screen object cleanups Remove unused member. No need to pin / unpin fb. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 0660d3c6b826..edfecc79d957 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -39,7 +39,6 @@ struct vmw_screen_object_display { struct list_head active; unsigned num_active; - unsigned last_num_active; struct vmw_framebuffer *fb; }; @@ -84,12 +83,8 @@ static int vmw_sou_del_active(struct vmw_private *vmw_priv, /* Must init otherwise list_empty(&sou->active) will not work. */ list_del_init(&sou->active); - if (--(ld->num_active) == 0) { - BUG_ON(!ld->fb); - if (ld->fb->unpin) - ld->fb->unpin(ld->fb); + if (--(ld->num_active) == 0) ld->fb = NULL; - } return 0; } @@ -103,13 +98,7 @@ static int vmw_sou_add_active(struct vmw_private *vmw_priv, struct list_head *at; BUG_ON(!ld->num_active && ld->fb); - if (vfb != ld->fb) { - if (ld->fb && ld->fb->unpin) - ld->fb->unpin(ld->fb); - if (vfb->pin) - vfb->pin(vfb); - ld->fb = vfb; - } + ld->fb = vfb; if (!list_empty(&sou->active)) return 0; @@ -522,7 +511,6 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) INIT_LIST_HEAD(&dev_priv->sou_priv->active); dev_priv->sou_priv->num_active = 0; - dev_priv->sou_priv->last_num_active = 0; dev_priv->sou_priv->fb = NULL; ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); From 0e708bc5d6403d1a64a0e4155f1b91e318318989 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 2 Nov 2011 09:43:09 +0100 Subject: [PATCH 1551/1596] vmwgfx: Remove screen object active list It isn't used for anything. Replace with an active bool. Also make a couple of functions return void instead of int since their return value wasn't checked anyway. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakbo Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 52 ++++++++-------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index edfecc79d957..ea6583433a16 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -36,8 +36,6 @@ container_of(x, struct vmw_screen_object_unit, base.connector) struct vmw_screen_object_display { - struct list_head active; - unsigned num_active; struct vmw_framebuffer *fb; @@ -53,13 +51,11 @@ struct vmw_screen_object_unit { struct vmw_dma_buffer *buffer; /**< Backing store buffer */ bool defined; - - struct list_head active; + bool active; }; static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) { - list_del_init(&sou->active); vmw_display_unit_cleanup(&sou->base); kfree(sou); } @@ -74,48 +70,31 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) vmw_sou_destroy(vmw_crtc_to_sou(crtc)); } -static int vmw_sou_del_active(struct vmw_private *vmw_priv, +static void vmw_sou_del_active(struct vmw_private *vmw_priv, struct vmw_screen_object_unit *sou) { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - if (list_empty(&sou->active)) - return 0; - - /* Must init otherwise list_empty(&sou->active) will not work. */ - list_del_init(&sou->active); - if (--(ld->num_active) == 0) - ld->fb = NULL; - return 0; + if (sou->active) { + if (--(ld->num_active) == 0) + ld->fb = NULL; + sou->active = false; + } } -static int vmw_sou_add_active(struct vmw_private *vmw_priv, +static void vmw_sou_add_active(struct vmw_private *vmw_priv, struct vmw_screen_object_unit *sou, struct vmw_framebuffer *vfb) { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - struct vmw_screen_object_unit *entry; - struct list_head *at; BUG_ON(!ld->num_active && ld->fb); - ld->fb = vfb; - if (!list_empty(&sou->active)) - return 0; - - at = &ld->active; - list_for_each_entry(entry, &ld->active, active) { - if (entry->base.unit > sou->base.unit) - break; - - at = &entry->active; + if (!sou->active) { + ld->fb = vfb; + sou->active = true; + ld->num_active++; } - - list_add(&sou->active, at); - - ld->num_active++; - - return 0; } /** @@ -303,7 +282,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) /* sou only supports one fb active at the time */ if (dev_priv->sou_priv->fb && vfb && !(dev_priv->sou_priv->num_active == 1 && - !list_empty(&sou->active)) && + sou->active) && dev_priv->sou_priv->fb != vfb) { DRM_ERROR("Multiple framebuffers not supported\n"); return -EINVAL; @@ -460,7 +439,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) encoder = &sou->base.encoder; connector = &sou->base.connector; - INIT_LIST_HEAD(&sou->active); + sou->active = false; sou->base.pref_active = (unit == 0); sou->base.pref_width = 800; @@ -509,7 +488,6 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) if (unlikely(!dev_priv->sou_priv)) goto err_no_mem; - INIT_LIST_HEAD(&dev_priv->sou_priv->active); dev_priv->sou_priv->num_active = 0; dev_priv->sou_priv->fb = NULL; @@ -546,7 +524,7 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) drm_vblank_cleanup(dev); - if (!list_empty(&dev_priv->sou_priv->active)) + if (dev_priv->sou_priv->num_active > 0) DRM_ERROR("Still have active outputs when unloading driver"); kfree(dev_priv->sou_priv); From 1543b4dd0c4b63975ffdadccd67c3a8805f28814 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 2 Nov 2011 09:43:10 +0100 Subject: [PATCH 1552/1596] vmwgfx: Make the preferred autofit mode have a 60Hz vrefresh Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index f9a0f980c300..1cebf64f1142 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1662,6 +1662,28 @@ static struct drm_display_mode vmw_kms_connector_builtin[] = { { DRM_MODE("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }, }; +/** + * vmw_guess_mode_timing - Provide fake timings for a + * 60Hz vrefresh mode. + * + * @mode - Pointer to a struct drm_display_mode with hdisplay and vdisplay + * members filled in. + */ +static void vmw_guess_mode_timing(struct drm_display_mode *mode) +{ + mode->hsync_start = mode->hdisplay + 50; + mode->hsync_end = mode->hsync_start + 50; + mode->htotal = mode->hsync_end + 50; + + mode->vsync_start = mode->vdisplay + 50; + mode->vsync_end = mode->vsync_start + 50; + mode->vtotal = mode->vsync_end + 50; + + mode->clock = (u32)mode->htotal * (u32)mode->vtotal / 100 * 6; + mode->vrefresh = drm_mode_vrefresh(mode); +} + + int vmw_du_connector_fill_modes(struct drm_connector *connector, uint32_t max_width, uint32_t max_height) { @@ -1684,7 +1706,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, return 0; mode->hdisplay = du->pref_width; mode->vdisplay = du->pref_height; - mode->vrefresh = drm_mode_vrefresh(mode); + vmw_guess_mode_timing(mode); if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2, mode->vdisplay)) { drm_mode_probed_add(connector, mode); From 6987427a3953c5038dc14d2a090b5a6c93669428 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 2 Nov 2011 09:43:11 +0100 Subject: [PATCH 1553/1596] vmwgfx: Infrastructure for explicit placement Make it possible to use explicit placement (although not hooked up with a user-space interface yet) and relax the single framebuffer limit to only apply to implicit placement. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 52 +++++++++++++++------------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 815cf99ce06e..af8e6e5bd964 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -102,6 +102,7 @@ struct vmw_display_unit { */ int gui_x; int gui_y; + bool is_implicit; }; #define vmw_crtc_to_du(x) \ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index bbfe38194910..90c5e3928491 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -337,6 +337,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) ldu->base.pref_width = 800; ldu->base.pref_height = 600; ldu->base.pref_mode = NULL; + ldu->base.is_implicit = true; drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index ea6583433a16..4defdcf1c72e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -36,9 +36,9 @@ container_of(x, struct vmw_screen_object_unit, base.connector) struct vmw_screen_object_display { - unsigned num_active; + unsigned num_implicit; - struct vmw_framebuffer *fb; + struct vmw_framebuffer *implicit_fb; }; /** @@ -51,7 +51,7 @@ struct vmw_screen_object_unit { struct vmw_dma_buffer *buffer; /**< Backing store buffer */ bool defined; - bool active; + bool active_implicit; }; static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) @@ -75,10 +75,10 @@ static void vmw_sou_del_active(struct vmw_private *vmw_priv, { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - if (sou->active) { - if (--(ld->num_active) == 0) - ld->fb = NULL; - sou->active = false; + if (sou->active_implicit) { + if (--(ld->num_implicit) == 0) + ld->implicit_fb = NULL; + sou->active_implicit = false; } } @@ -88,12 +88,12 @@ static void vmw_sou_add_active(struct vmw_private *vmw_priv, { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - BUG_ON(!ld->num_active && ld->fb); + BUG_ON(!ld->num_implicit && ld->implicit_fb); - if (!sou->active) { - ld->fb = vfb; - sou->active = true; - ld->num_active++; + if (!sou->active_implicit && sou->base.is_implicit) { + ld->implicit_fb = vfb; + sou->active_implicit = true; + ld->num_implicit++; } } @@ -132,8 +132,13 @@ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); cmd->obj.size.width = mode->hdisplay; cmd->obj.size.height = mode->vdisplay; - cmd->obj.root.x = x; - cmd->obj.root.y = y; + if (sou->base.is_implicit) { + cmd->obj.root.x = x; + cmd->obj.root.y = y; + } else { + cmd->obj.root.x = sou->base.gui_x; + cmd->obj.root.y = sou->base.gui_y; + } /* Ok to assume that buffer is pinned in vram */ vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); @@ -280,10 +285,11 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) } /* sou only supports one fb active at the time */ - if (dev_priv->sou_priv->fb && vfb && - !(dev_priv->sou_priv->num_active == 1 && - sou->active) && - dev_priv->sou_priv->fb != vfb) { + if (sou->base.is_implicit && + dev_priv->sou_priv->implicit_fb && vfb && + !(dev_priv->sou_priv->num_implicit == 1 && + sou->active_implicit) && + dev_priv->sou_priv->implicit_fb != vfb) { DRM_ERROR("Multiple framebuffers not supported\n"); return -EINVAL; } @@ -439,12 +445,13 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) encoder = &sou->base.encoder; connector = &sou->base.connector; - sou->active = false; + sou->active_implicit = false; sou->base.pref_active = (unit == 0); sou->base.pref_width = 800; sou->base.pref_height = 600; sou->base.pref_mode = NULL; + sou->base.is_implicit = true; drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); @@ -488,8 +495,8 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) if (unlikely(!dev_priv->sou_priv)) goto err_no_mem; - dev_priv->sou_priv->num_active = 0; - dev_priv->sou_priv->fb = NULL; + dev_priv->sou_priv->num_implicit = 0; + dev_priv->sou_priv->implicit_fb = NULL; ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); if (unlikely(ret != 0)) @@ -524,9 +531,6 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) drm_vblank_cleanup(dev); - if (dev_priv->sou_priv->num_active > 0) - DRM_ERROR("Still have active outputs when unloading driver"); - kfree(dev_priv->sou_priv); return 0; From da7653d6a0dcf7c3a173c87df144735e61a86c1e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 2 Nov 2011 09:43:12 +0100 Subject: [PATCH 1554/1596] vmwgfx: Fix hw cursor position Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 1cebf64f1142..5ccce1c3daf9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -176,7 +176,9 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, return 0; } - vmw_cursor_update_position(dev_priv, true, du->cursor_x, du->cursor_y); + vmw_cursor_update_position(dev_priv, true, + du->cursor_x + du->hotspot_x, + du->cursor_y + du->hotspot_y); return 0; } @@ -191,7 +193,8 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) du->cursor_y = y + crtc->y; vmw_cursor_update_position(dev_priv, shown, - du->cursor_x, du->cursor_y); + du->cursor_x + du->hotspot_x, + du->cursor_y + du->hotspot_y); return 0; } From d982640914d74054d22508ccebeeda70ce5933e1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 3 Nov 2011 21:03:04 +0100 Subject: [PATCH 1555/1596] vmwgfx: Use pointer return error codes Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 5ccce1c3daf9..41a905d6c4f1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -997,7 +997,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, required_size = mode_cmd->pitch * mode_cmd->height; if (unlikely(required_size > (u64) dev_priv->vram_size)) { DRM_ERROR("VRAM size is too small for requested mode.\n"); - return NULL; + return ERR_PTR(-ENOMEM); } /* From 55bde5b215ceb8356328f18cd82a77843bc4ffd3 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 3 Nov 2011 21:03:05 +0100 Subject: [PATCH 1556/1596] vmwgfx: Free prefered mode on error path Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 41a905d6c4f1..667437b037f3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1710,17 +1710,22 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, mode->hdisplay = du->pref_width; mode->vdisplay = du->pref_height; vmw_guess_mode_timing(mode); + if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2, mode->vdisplay)) { drm_mode_probed_add(connector, mode); + } else { + drm_mode_destroy(dev, mode); + mode = NULL; + } - if (du->pref_mode) { - list_del_init(&du->pref_mode->head); - drm_mode_destroy(dev, du->pref_mode); - } - - du->pref_mode = mode; + if (du->pref_mode) { + list_del_init(&du->pref_mode->head); + drm_mode_destroy(dev, du->pref_mode); } + + /* mode might be null here, this is intended */ + du->pref_mode = mode; } for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { From e5c8dbb8141e7da81bd8179929d1298302d17128 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 3 Nov 2011 21:03:06 +0100 Subject: [PATCH 1557/1596] vmwgfx: Unreference surface on cursor error path Signed-off-by: Jakob Bornecrantz Reviewed-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 667437b037f3..66e92acb3c5b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -111,6 +111,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, if (!ret) { if (!surface->snooper.image) { DRM_ERROR("surface not suitable for cursor\n"); + vmw_surface_unreference(&surface); return -EINVAL; } } else { From d41025c0d6a7b3d80d68f07f943b72962d66ac74 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 3 Nov 2011 21:03:07 +0100 Subject: [PATCH 1558/1596] vmwgfx: Move the prefered mode first in the list Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 66e92acb3c5b..8de24836edb1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1747,6 +1747,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, drm_mode_probed_add(connector, mode); } + /* Move the prefered mode first, help apps pick the right mode. */ + if (du->pref_mode) + list_move(&du->pref_mode->head, &connector->probed_modes); + drm_mode_connector_list_update(connector); return 1; From 2ac863719e518ae1a8f328849e64ea26a222f079 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 3 Nov 2011 21:03:08 +0100 Subject: [PATCH 1559/1596] vmwgfx: Snoop DMA transfers with non-covering sizes Enough to get cursors working under Wayland. Signed-off-by: Jakob Bornecrantz Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 30 ++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 8de24836edb1..03daefa73397 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -216,7 +216,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, SVGA3dCmdHeader header; SVGA3dCmdSurfaceDMA dma; } *cmd; - int ret; + int i, ret; cmd = container_of(header, struct vmw_dma_cmd, header); @@ -238,16 +238,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) / sizeof(SVGA3dCopyBox); - if (cmd->dma.guest.pitch != (64 * 4) || - cmd->dma.guest.ptr.offset % PAGE_SIZE || + if (cmd->dma.guest.ptr.offset % PAGE_SIZE || box->x != 0 || box->y != 0 || box->z != 0 || box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || - box->w != 64 || box->h != 64 || box->d != 1 || - box_count != 1) { + box->d != 1 || box_count != 1) { /* TODO handle none page aligned offsets */ - /* TODO handle partial uploads and pitch != 256 */ - /* TODO handle more then one copy (size != 64) */ - DRM_ERROR("lazy programmer, can't handle weird stuff\n"); + /* TODO handle more dst & src != 0 */ + /* TODO handle more then one copy */ + DRM_ERROR("Cant snoop dma request for cursor!\n"); + DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n", + box->srcx, box->srcy, box->srcz, + box->x, box->y, box->z, + box->w, box->h, box->d, box_count, + cmd->dma.guest.ptr.offset); return; } @@ -266,7 +269,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, virtual = ttm_kmap_obj_virtual(&map, &dummy); - memcpy(srf->snooper.image, virtual, 64*64*4); + if (box->w == 64 && cmd->dma.guest.pitch == 64*4) { + memcpy(srf->snooper.image, virtual, 64*64*4); + } else { + /* Image is unsigned pointer. */ + for (i = 0; i < box->h; i++) + memcpy(srf->snooper.image + i * 64, + virtual + i * cmd->dma.guest.pitch, + box->w * 4); + } + srf->snooper.age++; /* we can't call this function from this function since execbuf has From 012641082b34433dac3cbb452e0a6ceccfd4643f Mon Sep 17 00:00:00 2001 From: "Rose, Gregory V" Date: Mon, 7 Nov 2011 07:44:17 +0000 Subject: [PATCH 1560/1596] ixgbe: Fix compile for kernel without CONFIG_PCI_IOV defined Fix compiler errors and warnings with CONFIG_PCI_IOV defined and not defined. Signed-off-by: Greg Rose Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 2 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index db95731863d7..00fcd39ad666 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -442,12 +442,14 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter) { +#ifdef CONFIG_PCI_IOV int i; for (i = 0; i < adapter->num_vfs; i++) { if (adapter->vfinfo[i].vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED) return true; } +#endif return false; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h index 4a5d8897faab..df04f1a3857c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h @@ -42,11 +42,11 @@ int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting); int ixgbe_ndo_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *ivi); void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter); -#ifdef CONFIG_PCI_IOV void ixgbe_disable_sriov(struct ixgbe_adapter *adapter); +int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter); +#ifdef CONFIG_PCI_IOV void ixgbe_enable_sriov(struct ixgbe_adapter *adapter, const struct ixgbe_info *ii); -int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter); #endif From 23ba07991dad5a96a024c1b45cb602eef5f83df8 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Mon, 7 Nov 2011 05:54:58 +0000 Subject: [PATCH 1561/1596] usbnet: fix oops in usbnet_start_xmit This patch fixes the bug added in commit v3.1-rc7-1055-gf9b491e SKB can be NULL at this point, at least for cdc-ncm. Signed-off-by: Konstantin Khlebnikov Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 7d6082160bcc..fae0fbd8bc88 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1057,7 +1057,8 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, unsigned long flags; int retval; - skb_tx_timestamp(skb); + if (skb) + skb_tx_timestamp(skb); // some devices want funky USB-level framing, for // win32 driver (usually) and/or hardware quirks From 039c811cb0e6c5696086072794bb79fc7011c765 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 7 Nov 2011 13:27:30 -0500 Subject: [PATCH 1562/1596] wanrouter: Remove kernel_lock annotations The BKL is gone, these annotations are useless. Signed-off-by: Richard Weinberger Signed-off-by: David S. Miller --- net/wanrouter/wanproc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c index f346395314ba..c43612ee96bb 100644 --- a/net/wanrouter/wanproc.c +++ b/net/wanrouter/wanproc.c @@ -81,7 +81,6 @@ static struct proc_dir_entry *proc_router; * Iterator */ static void *r_start(struct seq_file *m, loff_t *pos) - __acquires(kernel_lock) { struct wan_device *wandev; loff_t l = *pos; @@ -103,7 +102,6 @@ static void *r_next(struct seq_file *m, void *v, loff_t *pos) } static void r_stop(struct seq_file *m, void *v) - __releases(kernel_lock) { mutex_unlock(&config_mutex); } From dd1294c4ed25725d13a6cb3d93ca0eb5fee14963 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 7 Nov 2011 13:28:20 -0500 Subject: [PATCH 1563/1596] MAINTAINERS/rds: update maintainer update for the actual maintainer Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ecb2299a1601..237c9ab22804 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5471,7 +5471,7 @@ S: Maintained F: drivers/net/ethernet/rdc/r6040.c RDS - RELIABLE DATAGRAM SOCKETS -M: Andy Grover +M: Venkat Venkatsubra L: rds-devel@oss.oracle.com (moderated for non-subscribers) S: Supported F: net/rds/ From 0c073e35550879fd133bc3fe509df5b88da51278 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sat, 8 Oct 2011 23:24:48 -0400 Subject: [PATCH 1564/1596] arm: Add export.h to recently added files for EXPORT_SYMBOL These files didn't exist at the time of the module.h split, and so were not fixed by the commits on that baseline. Since they use the EXPORT_SYMBOL and/or THIS_MODULE macros, they will need the new export.h file included that provides them. Signed-off-by: Paul Gortmaker Signed-off-by: Linus Torvalds --- arch/arm/plat-samsung/dma-ops.c | 1 + arch/arm/plat-samsung/s3c-dma-ops.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c index 6e3d9abc9e2e..93a994a5dd8f 100644 --- a/arch/arm/plat-samsung/dma-ops.c +++ b/arch/arm/plat-samsung/dma-ops.c @@ -14,6 +14,7 @@ #include #include #include +#include #include diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c index 582333c70585..781494912827 100644 --- a/arch/arm/plat-samsung/s3c-dma-ops.c +++ b/arch/arm/plat-samsung/s3c-dma-ops.c @@ -14,6 +14,7 @@ #include #include #include +#include #include From 1944ce60fe1e92506d3347f4d8e10a82b17096e4 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 28 Sep 2011 18:29:32 -0400 Subject: [PATCH 1565/1596] drivers/md: change module.h -> export.h in persistent-data/dm-* For the files which are not themselves modular, we can change them to include only the smaller export.h since all they are doing is looking for EXPORT_SYMBOL. Reported-by: Stephen Rothwell Signed-off-by: Paul Gortmaker Signed-off-by: Linus Torvalds --- drivers/md/persistent-data/dm-btree-remove.c | 2 +- drivers/md/persistent-data/dm-btree.c | 2 +- drivers/md/persistent-data/dm-space-map-disk.c | 2 +- drivers/md/persistent-data/dm-transaction-manager.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index 65fd85ec6514..023fbc2d389e 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -8,7 +8,7 @@ #include "dm-btree-internal.h" #include "dm-transaction-manager.h" -#include +#include /* * Removing an entry from a btree diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index e0638be53ea4..bd1e7ffbe26c 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -8,7 +8,7 @@ #include "dm-space-map.h" #include "dm-transaction-manager.h" -#include +#include #include #define DM_MSG_PREFIX "btree" diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c index aeff7852cf79..fc469ba9f627 100644 --- a/drivers/md/persistent-data/dm-space-map-disk.c +++ b/drivers/md/persistent-data/dm-space-map-disk.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #define DM_MSG_PREFIX "space map disk" diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c index 728e89a3f978..6f8d38747d7f 100644 --- a/drivers/md/persistent-data/dm-transaction-manager.c +++ b/drivers/md/persistent-data/dm-transaction-manager.c @@ -10,7 +10,7 @@ #include "dm-space-map-metadata.h" #include "dm-persistent-data-internal.h" -#include +#include #include #include From 6f66263f8ebe1fb1f138de41ca9aa0a4860b30d0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 1 Nov 2011 18:30:49 +1100 Subject: [PATCH 1566/1596] device-mapper: dm-bufio.c needs to include module.h since it uses the module facilities. Reported-by: Witold Baryluk Signed-off-by: Stephen Rothwell Signed-off-by: Paul Gortmaker Signed-off-by: Linus Torvalds --- drivers/md/dm-bufio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index cb246667dd52..0a6806f80ab5 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -14,6 +14,7 @@ #include #include #include +#include #define DM_MSG_PREFIX "bufio" From a84450604d0fe08b6a2335efbedede18d3d7cc75 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 1 Nov 2011 20:27:43 +1100 Subject: [PATCH 1567/1596] device-mapper: using EXPORT_SYBOL in dm-space-map-checker.c needs export.h Reported-by: Witold Baryluk Signed-off-by: Stephen Rothwell Signed-off-by: Paul Gortmaker Signed-off-by: Linus Torvalds --- drivers/md/persistent-data/dm-space-map-checker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c index bb44a937fe63..50ed53bf4aa2 100644 --- a/drivers/md/persistent-data/dm-space-map-checker.c +++ b/drivers/md/persistent-data/dm-space-map-checker.c @@ -7,6 +7,7 @@ #include "dm-space-map-checker.h" #include +#include #ifdef CONFIG_DM_DEBUG_SPACE_MAPS From f9c4082df59e43c6667db197a4fb3eb3286f3fc1 Mon Sep 17 00:00:00 2001 From: david decotigny Date: Sat, 5 Nov 2011 14:38:20 +0000 Subject: [PATCH 1568/1596] forcedeth: fix race when unloading module When forcedeth module is unloaded, there exists a path that can lead to mod_timer() after del_timer_sync(), causing an oops. This patch short-circuits this unneeded path, which originates in nv_get_ethtool_stats(). Tested: x86_64 16-way + 3 ethtool -S infinite loops + 100Mbps incoming traffic + rmmod/modprobe/ifconfig in a loop Initial-Author: Salman Qazi Discussion: http://patchwork.ozlabs.org/patch/123548/ Signed-off-by: David Decotigny Signed-off-by: David S. Miller --- drivers/net/ethernet/nvidia/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 1e37eb98c4e2..344cb5fa512d 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -4566,7 +4566,7 @@ static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *e struct fe_priv *np = netdev_priv(dev); /* update stats */ - nv_do_stats_poll((unsigned long)dev); + nv_get_hw_stats(dev); memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64)); } From 2a4e7a085fb44369c450c92cf8bd53b91f874a57 Mon Sep 17 00:00:00 2001 From: Mike Ditto Date: Sat, 5 Nov 2011 14:38:21 +0000 Subject: [PATCH 1569/1596] forcedeth: Acknowledge only interrupts that are being processed This is to avoid a race, accidentally acknowledging an interrupt that we didn't notice and won't immediately process. This is based solely on code inspection; it is not known if there was an actual bug here. Signed-off-by: David Decotigny Signed-off-by: David S. Miller --- drivers/net/ethernet/nvidia/forcedeth.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 344cb5fa512d..b7cf4b6e15ec 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -3398,7 +3398,8 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL; - writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "tx irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3509,7 +3510,8 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; - writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "rx irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3553,7 +3555,8 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER; - writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3617,10 +3620,10 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data) if (!(np->msi_flags & NV_MSI_X_ENABLED)) { events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; - writel(NVREG_IRQ_TIMER, base + NvRegIrqStatus); + writel(events & NVREG_IRQ_TIMER, base + NvRegIrqStatus); } else { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; - writel(NVREG_IRQ_TIMER, base + NvRegMSIXIrqStatus); + writel(events & NVREG_IRQ_TIMER, base + NvRegMSIXIrqStatus); } pci_push(base); if (!(events & NVREG_IRQ_TIMER)) From 4687f3f364a1d5b2df815a8c58a763cab57724e8 Mon Sep 17 00:00:00 2001 From: david decotigny Date: Sat, 5 Nov 2011 14:38:22 +0000 Subject: [PATCH 1570/1596] forcedeth: remove unneeded stats updates Function ndo_get_stats() updates most of the stats from hardware registers, making the manual updates un-needed. This change removes these manual updates. Main exception is rx_missed_errors which needs manual update. Another exception is rx_packets, still updated manually in this commit to make sure this patch doesn't change behavior of driver. This will be addressed by a future patch. Signed-off-by: David Decotigny Signed-off-by: David S. Miller --- drivers/net/ethernet/nvidia/forcedeth.c | 35 +------------------------ 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index b7cf4b6e15ec..2f1eaee5cf00 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -2374,16 +2374,8 @@ static int nv_tx_done(struct net_device *dev, int limit) if (np->desc_ver == DESC_VER_1) { if (flags & NV_TX_LASTPACKET) { if (flags & NV_TX_ERROR) { - if (flags & NV_TX_UNDERFLOW) - dev->stats.tx_fifo_errors++; - if (flags & NV_TX_CARRIERLOST) - dev->stats.tx_carrier_errors++; if ((flags & NV_TX_RETRYERROR) && !(flags & NV_TX_RETRYCOUNT_MASK)) nv_legacybackoff_reseed(dev); - dev->stats.tx_errors++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += np->get_tx_ctx->skb->len; } dev_kfree_skb_any(np->get_tx_ctx->skb); np->get_tx_ctx->skb = NULL; @@ -2392,16 +2384,8 @@ static int nv_tx_done(struct net_device *dev, int limit) } else { if (flags & NV_TX2_LASTPACKET) { if (flags & NV_TX2_ERROR) { - if (flags & NV_TX2_UNDERFLOW) - dev->stats.tx_fifo_errors++; - if (flags & NV_TX2_CARRIERLOST) - dev->stats.tx_carrier_errors++; if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) nv_legacybackoff_reseed(dev); - dev->stats.tx_errors++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += np->get_tx_ctx->skb->len; } dev_kfree_skb_any(np->get_tx_ctx->skb); np->get_tx_ctx->skb = NULL; @@ -2434,9 +2418,7 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit) nv_unmap_txskb(np, np->get_tx_ctx); if (flags & NV_TX2_LASTPACKET) { - if (!(flags & NV_TX2_ERROR)) - dev->stats.tx_packets++; - else { + if (flags & NV_TX2_ERROR) { if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) { if (np->driver_data & DEV_HAS_GEAR_MODE) nv_gear_backoff_reseed(dev); @@ -2636,7 +2618,6 @@ static int nv_rx_process(struct net_device *dev, int limit) if ((flags & NV_RX_ERROR_MASK) == NV_RX_ERROR4) { len = nv_getlen(dev, skb->data, len); if (len < 0) { - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2650,11 +2631,6 @@ static int nv_rx_process(struct net_device *dev, int limit) else { if (flags & NV_RX_MISSEDFRAME) dev->stats.rx_missed_errors++; - if (flags & NV_RX_CRCERR) - dev->stats.rx_crc_errors++; - if (flags & NV_RX_OVERFLOW) - dev->stats.rx_over_errors++; - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2670,7 +2646,6 @@ static int nv_rx_process(struct net_device *dev, int limit) if ((flags & NV_RX2_ERROR_MASK) == NV_RX2_ERROR4) { len = nv_getlen(dev, skb->data, len); if (len < 0) { - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2682,11 +2657,6 @@ static int nv_rx_process(struct net_device *dev, int limit) } /* the rest are hard errors */ else { - if (flags & NV_RX2_CRCERR) - dev->stats.rx_crc_errors++; - if (flags & NV_RX2_OVERFLOW) - dev->stats.rx_over_errors++; - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2704,7 +2674,6 @@ static int nv_rx_process(struct net_device *dev, int limit) skb->protocol = eth_type_trans(skb, dev); napi_gro_receive(&np->napi, skb); dev->stats.rx_packets++; - dev->stats.rx_bytes += len; next_pkt: if (unlikely(np->get_rx.orig++ == np->last_rx.orig)) np->get_rx.orig = np->first_rx.orig; @@ -2787,9 +2756,7 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit) __vlan_hwaccel_put_tag(skb, vid); } napi_gro_receive(&np->napi, skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; } else { dev_kfree_skb(skb); } From 0bdfea8ba856826f5901fda608013f323c87f661 Mon Sep 17 00:00:00 2001 From: Mandeep Baines Date: Sat, 5 Nov 2011 14:38:23 +0000 Subject: [PATCH 1571/1596] forcedeth: Improve stats counters Rx byte count was off; instead use the hardware's count. Tx packet count was counting pre-TSO packets; instead count on-the-wire packets. Report hardware dropped frame count as rx_fifo_errors. - The count of transmitted packets reported by the forcedeth driver reports pre-TSO (TCP Segmentation Offload) packet counts and not the count of the number of packets sent on the wire. This change fixes the forcedeth driver to report the correct count. Fixed the code by copying the count stored in the NIC H/W to the value reported by the driver. - Count rx_drop_frame errors as rx_fifo_errors: We see a lot of rx_drop_frame errors if we disable the rx bottom-halves for too long. Normally, rx_fifo_errors would be counted in this case. The rx_drop_frame error count is private to forcedeth and is not reported by ifconfig or sysfs. The rx_fifo_errors count is currently unused in the forcedeth driver. It is reported by ifconfig as overruns. This change reports rx_drop_frame errors as rx_fifo_errors. Signed-off-by: David Decotigny Signed-off-by: David S. Miller --- drivers/net/ethernet/nvidia/forcedeth.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 2f1eaee5cf00..0c10ff700cbc 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -1682,6 +1682,7 @@ static void nv_get_hw_stats(struct net_device *dev) np->estats.tx_pause += readl(base + NvRegTxPause); np->estats.rx_pause += readl(base + NvRegRxPause); np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); + np->estats.rx_errors_total += np->estats.rx_drop_frame; } if (np->driver_data & DEV_HAS_STATISTICS_V3) { @@ -1706,11 +1707,14 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) nv_get_hw_stats(dev); /* copy to net_device stats */ + dev->stats.tx_packets = np->estats.tx_packets; + dev->stats.rx_bytes = np->estats.rx_bytes; dev->stats.tx_bytes = np->estats.tx_bytes; dev->stats.tx_fifo_errors = np->estats.tx_fifo_errors; dev->stats.tx_carrier_errors = np->estats.tx_carrier_errors; dev->stats.rx_crc_errors = np->estats.rx_crc_errors; dev->stats.rx_over_errors = np->estats.rx_over_errors; + dev->stats.rx_fifo_errors = np->estats.rx_drop_frame; dev->stats.rx_errors = np->estats.rx_errors_total; dev->stats.tx_errors = np->estats.tx_errors_total; } From e45a618753d5a8bc9086382f73bbc2d6a3399250 Mon Sep 17 00:00:00 2001 From: david decotigny Date: Sat, 5 Nov 2011 14:38:24 +0000 Subject: [PATCH 1572/1596] forcedeth: fix a few sparse warnings (variable shadowing) This fixes the following sparse warnings: drivers/net/ethernet/nvidia/forcedeth.c:2113:7: warning: symbol 'size' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2102:6: originally declared here drivers/net/ethernet/nvidia/forcedeth.c:2155:7: warning: symbol 'size' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2102:6: originally declared here drivers/net/ethernet/nvidia/forcedeth.c:2227:7: warning: symbol 'size' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2215:6: originally declared here drivers/net/ethernet/nvidia/forcedeth.c:2271:7: warning: symbol 'size' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2215:6: originally declared here drivers/net/ethernet/nvidia/forcedeth.c:2986:20: warning: symbol 'addr' shadows an earlier one drivers/net/ethernet/nvidia/forcedeth.c:2963:6: originally declared here Signed-off-by: David Decotigny Signed-off-by: David S. Miller --- drivers/net/ethernet/nvidia/forcedeth.c | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 0c10ff700cbc..1dca57013cb2 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -2103,10 +2103,10 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) /* add fragments to entries count */ for (i = 0; i < fragments; i++) { - u32 size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + u32 frag_size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - entries += (size >> NV_TX2_TSO_MAX_SHIFT) + - ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + entries += (frag_size >> NV_TX2_TSO_MAX_SHIFT) + + ((frag_size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } spin_lock_irqsave(&np->lock, flags); @@ -2145,13 +2145,13 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) /* setup the fragments */ for (i = 0; i < fragments; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 size = skb_frag_size(frag); + u32 frag_size = skb_frag_size(frag); offset = 0; do { prev_tx = put_tx; prev_tx_ctx = np->put_tx_ctx; - bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; np->put_tx_ctx->dma = skb_frag_dma_map( &np->pci_dev->dev, frag, offset, @@ -2163,12 +2163,12 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); offset += bcnt; - size -= bcnt; + frag_size -= bcnt; if (unlikely(put_tx++ == np->last_tx.orig)) put_tx = np->first_tx.orig; if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; - } while (size); + } while (frag_size); } /* set last fragment flag */ @@ -2217,10 +2217,10 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, /* add fragments to entries count */ for (i = 0; i < fragments; i++) { - u32 size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + u32 frag_size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - entries += (size >> NV_TX2_TSO_MAX_SHIFT) + - ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + entries += (frag_size >> NV_TX2_TSO_MAX_SHIFT) + + ((frag_size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } spin_lock_irqsave(&np->lock, flags); @@ -2261,13 +2261,13 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, /* setup the fragments */ for (i = 0; i < fragments; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 size = skb_frag_size(frag); + u32 frag_size = skb_frag_size(frag); offset = 0; do { prev_tx = put_tx; prev_tx_ctx = np->put_tx_ctx; - bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; np->put_tx_ctx->dma = skb_frag_dma_map( &np->pci_dev->dev, frag, offset, @@ -2280,12 +2280,12 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); offset += bcnt; - size -= bcnt; + frag_size -= bcnt; if (unlikely(put_tx++ == np->last_tx.ex)) put_tx = np->first_tx.ex; if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; - } while (size); + } while (frag_size); } /* set last fragment flag */ @@ -2933,11 +2933,11 @@ static void nv_set_multicast(struct net_device *dev) struct netdev_hw_addr *ha; netdev_for_each_mc_addr(ha, dev) { - unsigned char *addr = ha->addr; + unsigned char *hw_addr = ha->addr; u32 a, b; - a = le32_to_cpu(*(__le32 *) addr); - b = le16_to_cpu(*(__le16 *) (&addr[4])); + a = le32_to_cpu(*(__le32 *) hw_addr); + b = le16_to_cpu(*(__le16 *) (&hw_addr[4])); alwaysOn[0] &= a; alwaysOff[0] &= ~a; alwaysOn[1] &= b; From 50e696308c3fb18a4a0dae7b3a4d47469149c919 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 7 Nov 2011 16:39:57 +0000 Subject: [PATCH 1573/1596] vfs: d_invalidate() should leave mountpoints alone Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/dcache.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 274f13e2f094..a901c6901bce 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -546,9 +546,11 @@ int d_invalidate(struct dentry * dentry) * would make it unreachable from the root, * we might still populate it if it was a * working directory or similar). + * We also need to leave mountpoints alone, + * directory or not. */ - if (dentry->d_count > 1) { - if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { + if (dentry->d_count > 1 && dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) { spin_unlock(&dentry->d_lock); return -EBUSY; } From 5558141556d20f2bea7a664d70a867b8f64ca38d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 7 Nov 2011 12:27:10 -0800 Subject: [PATCH 1574/1596] ARM: OMAP: omap_device: Include linux/export.h Include linux/export.h to fix below build warning: CC arch/arm/plat-omap/omap_device.o arch/arm/plat-omap/omap_device.c:1055: warning: data definition has no type or storage class arch/arm/plat-omap/omap_device.c:1055: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' arch/arm/plat-omap/omap_device.c:1055: warning: parameter names (without types) in function declaration Signed-off-by: Axel Lin Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/omap_device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index cd90bedd9306..f839f948421a 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -78,6 +78,7 @@ #undef DEBUG #include +#include #include #include #include From a1bcc1dcef8451b4291ea2a1b2677cb194102952 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 7 Nov 2011 12:27:10 -0800 Subject: [PATCH 1575/1596] ARM: OMAP: Fix export.h or module.h includes Commit 32aaeffbd4a7457bf2f7448b33b5946ff2a960eb (Merge branch 'modsplit-Oct31_2011'...) caused some build errors. Fix these and make sure we always have export.h or module.h included for MODULE_ and EXPORT_SYMBOL users: $ grep -rl ^MODULE_ arch/arm/*omap*/*.c | xargs \ grep -L linux/module.h arch/arm/mach-omap2/dsp.c arch/arm/mach-omap2/mailbox.c arch/arm/mach-omap2/omap-iommu.c arch/arm/mach-omap2/smartreflex.c Also check we either have export.h or module.h included for the files exporting symbols: $ grep -rl EXPORT_SYMBOL arch/arm/*omap*/*.c | xargs \ grep -L linux/export.h | xargs grep -L linux/module.h Cc: Russell King Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/dsp.c | 1 + arch/arm/mach-omap2/mailbox.c | 1 + arch/arm/mach-omap2/omap-iommu.c | 1 + arch/arm/mach-omap2/smartreflex.c | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/arm/mach-omap2/dsp.c b/arch/arm/mach-omap2/dsp.c index 911cd2e68d46..74f18f2952df 100644 --- a/arch/arm/mach-omap2/dsp.c +++ b/arch/arm/mach-omap2/dsp.c @@ -18,6 +18,7 @@ * of the OMAP PM core code. */ +#include #include #include "cm2xxx_3xxx.h" #include "prm2xxx_3xxx.h" diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 86d564a640bb..609ea2ded7e3 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -10,6 +10,7 @@ * for more details. */ +#include #include #include #include diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index e61feadcda4e..b8822048e409 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index 0347b93211e6..6a4f6839a7d9 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -17,6 +17,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include From a6f05b97d1ba87326bd96f3da9fef994830d6994 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 6 Nov 2011 21:54:12 +0100 Subject: [PATCH 1576/1596] PM / QoS: Set cpu_dma_pm_qos->name Since commit 4a31a334, the name of this misc device is not initialized, which leads to a funny device named /dev/(null) being created and /proc/misc containing an entry with just a number but no name. The latter leads to complaints by cryptsetup, which caused me to investigate this matter. Signed-off-by: Dominik Brodowski Signed-off-by: Rafael J. Wysocki --- kernel/power/qos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 56db75147186..995e3bd3417b 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -70,6 +70,7 @@ static struct pm_qos_constraints cpu_dma_constraints = { }; static struct pm_qos_object cpu_dma_pm_qos = { .constraints = &cpu_dma_constraints, + .name = "cpu_dma_latency", }; static BLOCKING_NOTIFIER_HEAD(network_lat_notifier); From 5f11161675be1351cadb96c83850e20bf5bcdc48 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 6 Nov 2011 22:00:20 +0100 Subject: [PATCH 1577/1596] Documentation: Fix typo in freezer-subsystem.txt Fix a typo in Documentation/cgroups/freezer-subsystem.txt. Signed-off-by: Rafael J. Wysocki Reviewed-by: Srivatsa S. Bhat Acked-by: Randy Dunlap --- Documentation/cgroups/freezer-subsystem.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/cgroups/freezer-subsystem.txt b/Documentation/cgroups/freezer-subsystem.txt index c21d77742a07..7e62de1e59ff 100644 --- a/Documentation/cgroups/freezer-subsystem.txt +++ b/Documentation/cgroups/freezer-subsystem.txt @@ -33,9 +33,9 @@ demonstrate this problem using nested bash shells: From a second, unrelated bash shell: $ kill -SIGSTOP 16690 - $ kill -SIGCONT 16990 + $ kill -SIGCONT 16690 - + This happens because bash can observe both signals and choose how it responds to them. From 1a51cfdc4516a6e1f2c1f8a579630a027c30331a Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 7 Nov 2011 23:54:53 +0100 Subject: [PATCH 1578/1596] PM / devfreq: fix private_data The "private_date" field in struct devfreq_dev_status almost certainly wants to be "private_data"; since there are no in-tree users of this functionality, now seems like an easy time to make the fix. Signed-off-by: Jonathan Corbet Signed-off-by: Rafael J. Wysocki --- include/linux/devfreq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index afb94583960c..98ce8124b1cc 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -41,7 +41,7 @@ struct devfreq_dev_status { unsigned long total_time; unsigned long busy_time; unsigned long current_frequency; - void *private_date; + void *private_data; }; /** From a3fbbde70a0cec017f2431e8f8de208708c76acc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 7 Nov 2011 21:21:26 +0000 Subject: [PATCH 1579/1596] VFS: we need to set LOOKUP_JUMPED on mountpoint crossing Mountpoint crossing is similar to following procfs symlinks - we do not get ->d_revalidate() called for dentry we have arrived at, with unpleasant consequences for NFS4. Simple way to reproduce the problem in mainline: cat >/tmp/a.c <<'EOF' #include #include #include main() { struct flock fl = {.l_type = F_RDLCK, .l_whence = SEEK_SET, .l_len = 1}; if (fcntl(0, F_SETLK, &fl)) perror("setlk"); } EOF cc /tmp/a.c -o /tmp/test then on nfs4: mount --bind file1 file2 /tmp/test < file1 # ok /tmp/test < file2 # spews "setlk: No locks available"... What happens is the missing call of ->d_revalidate() after mountpoint crossing and that's where NFS4 would issue OPEN request to server. The fix is simple - treat mountpoint crossing the same way we deal with following procfs-style symlinks. I.e. set LOOKUP_JUMPED... Cc: stable@kernel.org Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/namei.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index ac6d214da827..5008f01787f5 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -852,7 +852,7 @@ static int follow_managed(struct path *path, unsigned flags) mntput(path->mnt); if (ret == -EISDIR) ret = 0; - return ret; + return ret < 0 ? ret : need_mntput; } int follow_down_one(struct path *path) @@ -900,6 +900,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, break; path->mnt = mounted; path->dentry = mounted->mnt_root; + nd->flags |= LOOKUP_JUMPED; nd->seq = read_seqcount_begin(&path->dentry->d_seq); /* * Update the inode too. We don't need to re-check the @@ -1213,6 +1214,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, path_put_conditional(path, nd); return err; } + if (err) + nd->flags |= LOOKUP_JUMPED; *inode = path->dentry->d_inode; return 0; } @@ -2146,6 +2149,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, } /* create side of things */ + /* + * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been + * cleared when we got to the last component we are about to look up + */ error = complete_walk(nd); if (error) return ERR_PTR(error); @@ -2214,6 +2221,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, if (error < 0) goto exit_dput; + if (error) + nd->flags |= LOOKUP_JUMPED; + error = -ENOENT; if (!path->dentry->d_inode) goto exit_dput; @@ -2223,6 +2233,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, path_to_nameidata(path, nd); nd->inode = path->dentry->d_inode; + /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ + error = complete_walk(nd); + if (error) + goto exit; error = -EISDIR; if (S_ISDIR(nd->inode->i_mode)) goto exit; From 1ea6b8f48918282bdca0b32a34095504ee65bab5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 7 Nov 2011 16:16:02 -0800 Subject: [PATCH 1580/1596] Linux 3.2-rc1 .. with new name. Because nothing says "really solid kernel release" like naming it after an extinct animal that just happened to be in the news lately. --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ed25c5b35470..361e4f00e6b9 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ VERSION = 3 -PATCHLEVEL = 1 +PATCHLEVEL = 2 SUBLEVEL = 0 -EXTRAVERSION = -NAME = "Divemaster Edition" +EXTRAVERSION = -rc1 +NAME = Saber-toothed Squirrel # *DOCUMENTATION* # To see a list of typical targets execute "make help" From 4e549d6d4a32d1a610ad081841d575f64087744a Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Sun, 6 Nov 2011 12:57:31 +0100 Subject: [PATCH 1581/1596] MTD: MAPS: bcm963xx-flash.c: explicitly include module.h module.h was previously implicitly included through mtd/mtd.h. Fixes the following build failure after the module.h cleanup: CC drivers/mtd/maps/bcm963xx-flash.o drivers/mtd/maps/bcm963xx-flash.c: In function 'bcm963xx_probe': drivers/mtd/maps/bcm963xx-flash.c:208:29: error: 'THIS_MODULE' undeclared (first use in this function) [...] drivers/mtd/maps/bcm963xx-flash.c:276:1: warning: type defaults to 'int' in declaration of 'MODULE_AUTHOR' drivers/mtd/maps/bcm963xx-flash.c:276:15: warning: function declaration isn't a prototype make[7]: *** [drivers/mtd/maps/bcm963xx-flash.o] Error 1 Signed-off-by: Jonas Gorski Signed-off-by: Paul Gortmaker --- drivers/mtd/maps/bcm963xx-flash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c index 608967fe74c6..736ca10ca9f1 100644 --- a/drivers/mtd/maps/bcm963xx-flash.c +++ b/drivers/mtd/maps/bcm963xx-flash.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include From 8f7346bdea64f2e3d02b0bcaf456e391c4cba134 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 6 Nov 2011 21:16:51 +0800 Subject: [PATCH 1582/1596] hwspinlock/u8500: include linux/module.h Include module.h to fix below build error: CC drivers/hwspinlock/u8500_hsem.o drivers/hwspinlock/u8500_hsem.c:177: error: 'THIS_MODULE' undeclared here (not in a function) [...] drivers/hwspinlock/u8500_hsem.c:196: warning: type defaults to 'int' in declaration of 'MODULE_AUTHOR' drivers/hwspinlock/u8500_hsem.c:196: warning: function declaration isn't a prototype make[2]: *** [drivers/hwspinlock/u8500_hsem.o] Error 1 make[1]: *** [drivers/hwspinlock] Error 2 make: *** [drivers] Error 2 Signed-off-by: Axel Lin Signed-off-by: Paul Gortmaker --- drivers/hwspinlock/u8500_hsem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c index 143461a95ae4..0156af510032 100644 --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -21,6 +21,7 @@ * General Public License for more details. */ +#include #include #include #include From 3b8ce3aed986090d9249629f97c53b4dfb8c9783 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 7 Nov 2011 11:17:04 -0500 Subject: [PATCH 1583/1596] mfd: fix build failures in recently added ab5500 code These files had implicit dependencies on modular support which now show up as build failures with the module cleanup work merged to mainline. Reported-by: Axel Lin Signed-off-by: Paul Gortmaker --- drivers/mfd/ab5500-core.c | 1 + drivers/mfd/ab5500-debugfs.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c index 4175544b491b..ec10629a0b0b 100644 --- a/drivers/mfd/ab5500-core.c +++ b/drivers/mfd/ab5500-core.c @@ -13,6 +13,7 @@ * TODO: Event handling with irq_chip. Waiting for PRCMU fw support. */ +#include #include #include #include diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c index 6be1fe6b5f9a..43c0ebb81956 100644 --- a/drivers/mfd/ab5500-debugfs.c +++ b/drivers/mfd/ab5500-debugfs.c @@ -4,6 +4,7 @@ * Debugfs support for the AB5500 MFD driver */ +#include #include #include #include From 9a3f530f39f4490eaa18b02719fb74ce5f4d2d86 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 8 Nov 2011 16:22:01 +1100 Subject: [PATCH 1584/1596] md/raid5: abort any pending parity operations when array fails. When the number of failed devices exceeds the allowed number we must abort any active parity operations (checks or updates) as they are no longer meaningful, and can lead to a BUG_ON in handle_parity_checks6. This bug was introduce by commit 6c0069c0ae9659e3a91b68eaed06a5c6c37f45c8 in 2.6.29. Reported-by: Manish Katiyar Tested-by: Manish Katiyar Acked-by: Dan Williams Signed-off-by: NeilBrown Cc: stable@kernel.org --- drivers/md/raid5.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 472aedfb07cf..318bdae9b56c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3159,10 +3159,14 @@ static void handle_stripe(struct stripe_head *sh) /* check if the array has lost more than max_degraded devices and, * if so, some requests might need to be failed. */ - if (s.failed > conf->max_degraded && s.to_read+s.to_write+s.written) - handle_failed_stripe(conf, sh, &s, disks, &s.return_bi); - if (s.failed > conf->max_degraded && s.syncing) - handle_failed_sync(conf, sh, &s); + if (s.failed > conf->max_degraded) { + sh->check_state = 0; + sh->reconstruct_state = 0; + if (s.to_read+s.to_write+s.written) + handle_failed_stripe(conf, sh, &s, disks, &s.return_bi); + if (s.syncing) + handle_failed_sync(conf, sh, &s); + } /* * might be able to return some write requests if the parity blocks From 257a4b42af7586fab4eaec7f04e6896b86551843 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 8 Nov 2011 16:22:06 +1100 Subject: [PATCH 1585/1596] md/raid5: STRIPE_ACTIVE has lock semantics, add barriers All updates that occur under STRIPE_ACTIVE should be globally visible when STRIPE_ACTIVE clears. test_and_set_bit() implies a barrier, but clear_bit() does not. This is suitable for 3.1-stable. Signed-off-by: Dan Williams Signed-off-by: NeilBrown Cc: stable@kernel.org --- drivers/md/raid5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 318bdae9b56c..297e26092178 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3110,7 +3110,7 @@ static void handle_stripe(struct stripe_head *sh) struct r5dev *pdev, *qdev; clear_bit(STRIPE_HANDLE, &sh->state); - if (test_and_set_bit(STRIPE_ACTIVE, &sh->state)) { + if (test_and_set_bit_lock(STRIPE_ACTIVE, &sh->state)) { /* already being handled, ensure it gets handled * again when current action finishes */ set_bit(STRIPE_HANDLE, &sh->state); @@ -3375,7 +3375,7 @@ static void handle_stripe(struct stripe_head *sh) return_io(s.return_bi); - clear_bit(STRIPE_ACTIVE, &sh->state); + clear_bit_unlock(STRIPE_ACTIVE, &sh->state); } static void raid5_activate_delayed(struct r5conf *conf) From 816af3bb5022c1468b3d826c645ddc2cac45bc97 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 3 Nov 2011 14:45:48 +0800 Subject: [PATCH 1586/1596] hwspinlock: Don't return a value in __hwspin_unlock Fix below build warning: CC arch/arm/mach-omap2/hwspinlock.o In file included from arch/arm/mach-omap2/hwspinlock.c:22: include/linux/hwspinlock.h: In function '__hwspin_unlock': include/linux/hwspinlock.h:121: warning: 'return' with a value, in function returning void Signed-off-by: Axel Lin Signed-off-by: Ohad Ben-Cohen --- include/linux/hwspinlock.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h index 08a2fee40659..aad6bd4b3efd 100644 --- a/include/linux/hwspinlock.h +++ b/include/linux/hwspinlock.h @@ -118,7 +118,6 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags) static inline void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) { - return 0; } static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) From fdcb23634c9b6649bb02c681033d4973491b0e35 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 6 Nov 2011 21:14:16 +0800 Subject: [PATCH 1587/1596] hwspinlock/u8500: fix build error due to undefined label Fix below build error: CC drivers/hwspinlock/u8500_hsem.o drivers/hwspinlock/u8500_hsem.c: In function 'u8500_hsem_probe': drivers/hwspinlock/u8500_hsem.c:113: error: label 'free_state' used but not defined Signed-off-by: Axel Lin Signed-off-by: Ohad Ben-Cohen --- drivers/hwspinlock/u8500_hsem.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c index 143461a95ae4..a120f14814f9 100644 --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -108,10 +108,8 @@ static int __devinit u8500_hsem_probe(struct platform_device *pdev) return -ENODEV; io_base = ioremap(res->start, resource_size(res)); - if (!io_base) { - ret = -ENOMEM; - goto free_state; - } + if (!io_base) + return -ENOMEM; /* make sure protocol 1 is selected */ val = readl(io_base + HSEM_CTRL_REG); From a8d12007c795f3d69ee0b2d29f0abfefd55c6120 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 8 Nov 2011 18:02:10 +0000 Subject: [PATCH 1588/1596] n_gsm: Fix timings Alek Du reported that the code erroneously applies time to jiffies conversions twice to the t1 and t2 values. In normal use on a modem link this cases no visible problem but on a slower link it will break as with HZ=1000 as is typical we are running t1/t2 ten times too fast. Alek's original patch removed the conversion from the timer setting but we in fact have to be more careful as the contents of t1/t2 are visible via the device API and we thus need to correct the constants. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/tty/n_gsm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 4cb0d0a3e57b..fc7bbba585ce 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -66,14 +66,16 @@ static int debug; module_param(debug, int, 0600); -#define T1 (HZ/10) -#define T2 (HZ/3) -#define N2 3 +/* Defaults: these are from the specification */ + +#define T1 10 /* 100mS */ +#define T2 34 /* 333mS */ +#define N2 3 /* Retry 3 times */ /* Use long timers for testing at low speed with debug on */ #ifdef DEBUG_TIMING -#define T1 HZ -#define T2 (2 * HZ) +#define T1 100 +#define T2 200 #endif /* From 6aec187a90aeb883533c9180e2acac1e54c87f7d Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 8 Nov 2011 14:56:50 -0500 Subject: [PATCH 1589/1596] drivers/media: video/a5k6aa is a module and so needs module.h This file uses core functions like module_init() and module_exit() and so it explicitly needs to include the module.h header. Signed-off-by: Paul Gortmaker --- drivers/media/video/s5k6aa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c index 2446736b7871..0df7f2a41814 100644 --- a/drivers/media/video/s5k6aa.c +++ b/drivers/media/video/s5k6aa.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include From b9c913f327ccc5cf422b6dc9b5acfbc9b86e7b62 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 8 Nov 2011 12:17:25 -0800 Subject: [PATCH 1590/1596] x86 platform drivers: make Dell laptop driver select needed LED support Otherwise we get compile errors like this: ERROR: "led_classdev_unregister" [drivers/platform/x86/dell-laptop.ko] undefined! ERROR: "led_classdev_register" [drivers/platform/x86/dell-laptop.ko] undefined! make[1]: *** [__modpost] Error 1 make: *** [modules] Error 2 when the dell-laptop support is enabled without the necessary LED support being enabled. Reported-by: Alessandro Suardi Acked-by: Matthew Garrett Signed-off-by: Linus Torvalds --- drivers/platform/x86/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f4e3d82379d7..598d5b82a6bc 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -85,6 +85,8 @@ config DELL_LAPTOP depends on RFKILL || RFKILL = n depends on POWER_SUPPLY depends on SERIO_I8042 + select LEDS_CLASS + select NEW_LEDS default n ---help--- This driver adds support for rfkill and backlight control to Dell From dccefb3729c8c2b17e45c68cdc0d575f2473a5f0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 8 Nov 2011 12:49:29 -0800 Subject: [PATCH 1591/1596] x86 platform drivers: add POWER_SUPPLY to selected drivers for Dell The Kconfig loop detection goes crazy without this. Signed-off-by: Linus Torvalds --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 598d5b82a6bc..7f43cf86d776 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -83,8 +83,8 @@ config DELL_LAPTOP depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE depends on RFKILL || RFKILL = n - depends on POWER_SUPPLY depends on SERIO_I8042 + select POWER_SUPPLY select LEDS_CLASS select NEW_LEDS default n From 156acb166ea9a43d7fcdf9b8051694ce4e91dbfc Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Tue, 8 Nov 2011 22:34:00 +0100 Subject: [PATCH 1592/1596] PM / OPP: Use ERR_CAST instead of ERR_PTR(PTR_ERR()) Use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...)) [The semantic patch that makes this change is available in scripts/coccinelle/api/err_cast.cocci. More information about semantic patching is available at http://coccinelle.lip6.fr/] Signed-off-by: Thomas Meyer Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 434a6c011675..95706fa24c73 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -669,7 +669,7 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev) struct device_opp *dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) - return ERR_PTR(PTR_ERR(dev_opp)); /* matching type */ + return ERR_CAST(dev_opp); /* matching type */ return &dev_opp->head; } From 5e442a493fc59fa536c76db1fff5b49ca36a88c5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 9 Nov 2011 18:16:00 -0500 Subject: [PATCH 1593/1596] Revert "proc: fix races against execve() of /proc/PID/fd**" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit aa6afca5bcaba8101f3ea09d5c3e4100b2b9f0e5. It escalates of some of the google-chrome SELinux problems with ptrace ("Check failed: pid_ > 0. Did not find zygote process"), and Andrew says that it is also causing mystery lockdep reports. Reported-by: Alex Villacís Lasso Requested-by: James Morris Requested-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 146 +++++++++++++++---------------------------------- 1 file changed, 43 insertions(+), 103 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 2db1bd3173b2..851ba3dcdc29 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1652,46 +1652,12 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b return error; } -static int proc_pid_fd_link_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = dentry->d_inode; - struct task_struct *task = get_proc_task(inode); - int rc; - - if (task == NULL) - return -ESRCH; - - rc = -EACCES; - if (lock_trace(task)) - goto out_task; - - generic_fillattr(inode, stat); - unlock_trace(task); - rc = 0; -out_task: - put_task_struct(task); - return rc; -} - static const struct inode_operations proc_pid_link_inode_operations = { .readlink = proc_pid_readlink, .follow_link = proc_pid_follow_link, .setattr = proc_setattr, }; -static const struct inode_operations proc_fdinfo_link_inode_operations = { - .setattr = proc_setattr, - .getattr = proc_pid_fd_link_getattr, -}; - -static const struct inode_operations proc_fd_link_inode_operations = { - .readlink = proc_pid_readlink, - .follow_link = proc_pid_follow_link, - .setattr = proc_setattr, - .getattr = proc_pid_fd_link_getattr, -}; - /* building an inode */ @@ -1923,61 +1889,49 @@ static unsigned name_to_int(struct dentry *dentry) static int proc_fd_info(struct inode *inode, struct path *path, char *info) { - struct task_struct *task; - struct files_struct *files; + struct task_struct *task = get_proc_task(inode); + struct files_struct *files = NULL; struct file *file; int fd = proc_fd(inode); - int rc; - - task = get_proc_task(inode); - if (!task) - return -ENOENT; - - rc = -EACCES; - if (lock_trace(task)) - goto out_task; - - rc = -ENOENT; - files = get_files_struct(task); - if (files == NULL) - goto out_unlock; - /* - * We are not taking a ref to the file structure, so we must - * hold ->file_lock. - */ - spin_lock(&files->file_lock); - file = fcheck_files(files, fd); - if (file) { - unsigned int f_flags; - struct fdtable *fdt; - - fdt = files_fdtable(files); - f_flags = file->f_flags & ~O_CLOEXEC; - if (FD_ISSET(fd, fdt->close_on_exec)) - f_flags |= O_CLOEXEC; - - if (path) { - *path = file->f_path; - path_get(&file->f_path); + if (task) { + files = get_files_struct(task); + put_task_struct(task); + } + if (files) { + /* + * We are not taking a ref to the file structure, so we must + * hold ->file_lock. + */ + spin_lock(&files->file_lock); + file = fcheck_files(files, fd); + if (file) { + unsigned int f_flags; + struct fdtable *fdt; + + fdt = files_fdtable(files); + f_flags = file->f_flags & ~O_CLOEXEC; + if (FD_ISSET(fd, fdt->close_on_exec)) + f_flags |= O_CLOEXEC; + + if (path) { + *path = file->f_path; + path_get(&file->f_path); + } + if (info) + snprintf(info, PROC_FDINFO_MAX, + "pos:\t%lli\n" + "flags:\t0%o\n", + (long long) file->f_pos, + f_flags); + spin_unlock(&files->file_lock); + put_files_struct(files); + return 0; } - if (info) - snprintf(info, PROC_FDINFO_MAX, - "pos:\t%lli\n" - "flags:\t0%o\n", - (long long) file->f_pos, - f_flags); - rc = 0; - } else - rc = -ENOENT; - spin_unlock(&files->file_lock); - put_files_struct(files); - -out_unlock: - unlock_trace(task); -out_task: - put_task_struct(task); - return rc; + spin_unlock(&files->file_lock); + put_files_struct(files); + } + return -ENOENT; } static int proc_fd_link(struct inode *inode, struct path *path) @@ -2072,7 +2026,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir, spin_unlock(&files->file_lock); put_files_struct(files); - inode->i_op = &proc_fd_link_inode_operations; + inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; ei->op.proc_get_link = proc_fd_link; d_set_d_op(dentry, &tid_fd_dentry_operations); @@ -2104,12 +2058,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir, if (fd == ~0U) goto out; - result = ERR_PTR(-EACCES); - if (lock_trace(task)) - goto out; - result = instantiate(dir, dentry, task, &fd); - unlock_trace(task); out: put_task_struct(task); out_no_task: @@ -2129,28 +2078,23 @@ static int proc_readfd_common(struct file * filp, void * dirent, retval = -ENOENT; if (!p) goto out_no_task; - - retval = -EACCES; - if (lock_trace(p)) - goto out; - retval = 0; fd = filp->f_pos; switch (fd) { case 0: if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) - goto out_unlock; + goto out; filp->f_pos++; case 1: ino = parent_ino(dentry); if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) - goto out_unlock; + goto out; filp->f_pos++; default: files = get_files_struct(p); if (!files) - goto out_unlock; + goto out; rcu_read_lock(); for (fd = filp->f_pos-2; fd < files_fdtable(files)->max_fds; @@ -2174,9 +2118,6 @@ static int proc_readfd_common(struct file * filp, void * dirent, rcu_read_unlock(); put_files_struct(files); } - -out_unlock: - unlock_trace(p); out: put_task_struct(p); out_no_task: @@ -2254,7 +2195,6 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir, ei->fd = fd; inode->i_mode = S_IFREG | S_IRUSR; inode->i_fop = &proc_fdinfo_file_operations; - inode->i_op = &proc_fdinfo_link_inode_operations; d_set_d_op(dentry, &tid_fd_dentry_operations); d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ From 750a7eee7395492960a7aeb3a3a1aa74158ec326 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 11 Nov 2011 15:41:50 +0900 Subject: [PATCH 1594/1596] drivers: sh: Generalize runtime PM platform stub. The runtime PM platform support stub in use by ARM-based SH/R-Mobile platforms contains nothing that's specifically ARM-related and instead of wholly generic to anything using the clock framework. The recent runtime PM changes interact rather badly with the lazy disabling of clocks late in the boot process through the clock framework, leading to situations where the runtime suspend/resume paths are entered without a clock being actively driven due to having been lazily gated off. In order to correct this we can trivially tie in the aforementioned stub as a general fallback for all SH platforms that don't presently have their own runtime PM implementations (the corner case being SH-based SH-Mobile platforms, which have their own stub through the hwblk API -- which in turn has bitrotted and will be subsequently adapted to use the same stub as everyone else), regardless of whether the platforms choose to define power domains of their own or not. This fixes up regressions for clock framework users who also build in runtime PM support without any specific power domains of their own, which was previously causing the serial console to be lost when warring with lazy clock disabling. Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Makefile | 2 +- drivers/sh/Makefile | 8 ++++++++ {arch/arm/mach-shmobile => drivers/sh}/pm_runtime.c | 0 3 files changed, 9 insertions(+), 1 deletion(-) rename {arch/arm/mach-shmobile => drivers/sh}/pm_runtime.c (100%) diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 2aec2f732515..737bdc631b0d 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -3,7 +3,7 @@ # # Common objects -obj-y := timer.o console.o clock.o pm_runtime.o +obj-y := timer.o console.o clock.o # CPU objects obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 24e6cec0ae8d..67e272ab1623 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -7,3 +7,11 @@ obj-$(CONFIG_HAVE_CLK) += clk/ obj-$(CONFIG_MAPLE) += maple/ obj-$(CONFIG_SUPERHYWAY) += superhyway/ obj-$(CONFIG_GENERIC_GPIO) += pfc.o + +# +# For the moment we only use this framework for ARM-based SH/R-Mobile +# platforms and generic SH. SH-based SH-Mobile platforms are still using +# an older framework that is pending up-porting, at which point this +# special casing can go away. +# +obj-$(CONFIG_SUPERH)$(CONFIG_ARCH_SHMOBILE) += pm_runtime.o diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/drivers/sh/pm_runtime.c similarity index 100% rename from arch/arm/mach-shmobile/pm_runtime.c rename to drivers/sh/pm_runtime.c From d03299ee6020b0cc64fc4180162fb2e8795394e1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 11 Nov 2011 15:58:50 +0900 Subject: [PATCH 1595/1596] drivers: sh: Kill off dead pathname for runtime PM stub. Signed-off-by: Paul Mundt --- drivers/sh/pm_runtime.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c index bd5c6a3b8c55..afe9282629b9 100644 --- a/drivers/sh/pm_runtime.c +++ b/drivers/sh/pm_runtime.c @@ -1,7 +1,5 @@ /* - * arch/arm/mach-shmobile/pm_runtime.c - * - * Runtime PM support code for SuperH Mobile ARM + * Runtime PM support code * * Copyright (C) 2009-2010 Magnus Damm * From 79e7066415a8b12adbeacc41b3dc44423534b8be Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 11 Nov 2011 16:11:41 +0900 Subject: [PATCH 1596/1596] sh: clkfwk: Kill off remaining debugfs cruft. Now that all of the named string association with clocks has been migrated to clkdev lookups there's no meaningful named topology that can be constructed for a debugfs tree view. Get rid of the left over bits, and shrink struct clk a bit in the process. Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 87 ------------------------------------------ include/linux/sh_clk.h | 1 - 2 files changed, 88 deletions(-) diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 352036b1f9a2..db257a35e71a 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -225,9 +224,6 @@ int clk_reparent(struct clk *child, struct clk *parent) list_add(&child->sibling, &parent->children); child->parent = parent; - /* now do the debugfs renaming to reattach the child - to the proper parent */ - return 0; } @@ -685,89 +681,6 @@ static int __init clk_syscore_init(void) subsys_initcall(clk_syscore_init); #endif -/* - * debugfs support to trace clock tree hierarchy and attributes - */ -static struct dentry *clk_debugfs_root; - -static int clk_debugfs_register_one(struct clk *c) -{ - int err; - struct dentry *d; - struct clk *pa = c->parent; - char s[255]; - char *p = s; - - p += sprintf(p, "%p", c); - d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root); - if (!d) - return -ENOMEM; - c->dentry = d; - - d = debugfs_create_u8("usecount", S_IRUGO, c->dentry, (u8 *)&c->usecount); - if (!d) { - err = -ENOMEM; - goto err_out; - } - d = debugfs_create_u32("rate", S_IRUGO, c->dentry, (u32 *)&c->rate); - if (!d) { - err = -ENOMEM; - goto err_out; - } - d = debugfs_create_x32("flags", S_IRUGO, c->dentry, (u32 *)&c->flags); - if (!d) { - err = -ENOMEM; - goto err_out; - } - return 0; - -err_out: - debugfs_remove_recursive(c->dentry); - return err; -} - -static int clk_debugfs_register(struct clk *c) -{ - int err; - struct clk *pa = c->parent; - - if (pa && !pa->dentry) { - err = clk_debugfs_register(pa); - if (err) - return err; - } - - if (!c->dentry) { - err = clk_debugfs_register_one(c); - if (err) - return err; - } - return 0; -} - -static int __init clk_debugfs_init(void) -{ - struct clk *c; - struct dentry *d; - int err; - - d = debugfs_create_dir("clock", NULL); - if (!d) - return -ENOMEM; - clk_debugfs_root = d; - - list_for_each_entry(c, &clock_list, node) { - err = clk_debugfs_register(c); - if (err) - goto err_out; - } - return 0; -err_out: - debugfs_remove_recursive(clk_debugfs_root); - return err; -} -late_initcall(clk_debugfs_init); - static int __init clk_late_init(void) { unsigned long flags; diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index 9237c299641c..a20831cf336a 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h @@ -52,7 +52,6 @@ struct clk { unsigned long arch_flags; void *priv; - struct dentry *dentry; struct clk_mapping *mapping; struct cpufreq_frequency_table *freq_table; unsigned int nr_freqs;